diff --git a/Cargo.lock b/Cargo.lock index 596c87f..662fba9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,7 +96,7 @@ dependencies = [ "ndk-context", "ndk-sys 0.6.0+11769913", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -114,6 +114,56 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] + [[package]] name = "anyhow" version = "1.0.97" @@ -173,6 +223,15 @@ dependencies = [ "libloading 0.7.4", ] +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading 0.8.6", +] + [[package]] name = "async-broadcast" version = "0.7.2" @@ -383,7 +442,16 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ - "bit-vec", + "bit-vec 0.6.3", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec 0.8.0", ] [[package]] @@ -392,6 +460,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bit_field" version = "0.10.2" @@ -409,6 +483,9 @@ name = "bitflags" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +dependencies = [ + "serde", +] [[package]] name = "bitstream-io" @@ -520,7 +597,7 @@ dependencies = [ "polling", "rustix 0.38.44", "slab", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -532,7 +609,7 @@ dependencies = [ "calloop", "rustix 0.38.44", "wayland-backend", - "wayland-client", + "wayland-client 0.31.8", ] [[package]] @@ -632,7 +709,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c" dependencies = [ - "thiserror", + "thiserror 1.0.69", "x11rb", ] @@ -652,6 +729,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "com" version = "0.6.0" @@ -702,6 +785,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1017,6 +1110,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -1101,6 +1203,29 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1215,6 +1340,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "font-types" version = "0.7.3" @@ -1465,6 +1596,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glow" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "glutin_wgl_sys" version = "0.5.0" @@ -1474,6 +1617,15 @@ dependencies = [ "gl_generator", ] +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + [[package]] name = "gpu-alloc" version = "0.6.0" @@ -1501,9 +1653,21 @@ checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" dependencies = [ "log", "presser", - "thiserror", + "thiserror 1.0.69", "winapi", - "windows", + "windows 0.52.0", +] + +[[package]] +name = "gpu-allocator" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +dependencies = [ + "log", + "presser", + "thiserror 1.0.69", + "windows 0.58.0", ] [[package]] @@ -1513,10 +1677,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c" dependencies = [ "bitflags 2.9.0", - "gpu-descriptor-types", + "gpu-descriptor-types 0.1.2", "hashbrown 0.14.5", ] +[[package]] +name = "gpu-descriptor" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca" +dependencies = [ + "bitflags 2.9.0", + "gpu-descriptor-types 0.2.0", + "hashbrown 0.15.2", +] + [[package]] name = "gpu-descriptor-types" version = "0.1.2" @@ -1526,6 +1701,15 @@ dependencies = [ "bitflags 2.9.0", ] +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.9.0", +] + [[package]] name = "guillotiere" version = "0.6.2" @@ -1576,6 +1760,9 @@ name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", +] [[package]] name = "hassle-rs" @@ -1587,7 +1774,7 @@ dependencies = [ "com", "libc", "libloading 0.8.6", - "thiserror", + "thiserror 1.0.69", "widestring", "winapi", ] @@ -1643,7 +1830,7 @@ dependencies = [ "iced_widget", "iced_winit", "image 0.24.9", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1662,7 +1849,7 @@ dependencies = [ "palette", "rustc-hash 2.1.1", "smol_str", - "thiserror", + "thiserror 1.0.69", "web-time", ] @@ -1691,7 +1878,7 @@ dependencies = [ "etagere", "lru", "rustc-hash 2.1.1", - "wgpu", + "wgpu 0.19.4", ] [[package]] @@ -1713,7 +1900,7 @@ dependencies = [ "once_cell", "raw-window-handle", "rustc-hash 2.1.1", - "thiserror", + "thiserror 1.0.69", "unicode-segmentation", ] @@ -1727,7 +1914,7 @@ dependencies = [ "iced_tiny_skia", "iced_wgpu", "log", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1740,7 +1927,7 @@ dependencies = [ "iced_core", "iced_futures", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1776,8 +1963,8 @@ dependencies = [ "lyon", "once_cell", "rustc-hash 2.1.1", - "thiserror", - "wgpu", + "thiserror 1.0.69", + "wgpu 0.19.4", ] [[package]] @@ -1791,7 +1978,7 @@ dependencies = [ "num-traits", "once_cell", "rustc-hash 2.1.1", - "thiserror", + "thiserror 1.0.69", "unicode-segmentation", ] @@ -1806,7 +1993,7 @@ dependencies = [ "iced_runtime", "log", "rustc-hash 2.1.1", - "thiserror", + "thiserror 1.0.69", "tracing", "wasm-bindgen-futures", "web-sys", @@ -1871,12 +2058,17 @@ name = "imflow" version = "0.1.0" dependencies = [ "criterion", + "env_logger", "iced", "image 0.25.6", "itertools 0.12.1", "memmap2", + "minifb", + "pollster", "tokio", "tracing-subscriber", + "wgpu 24.0.3", + "winit", "zune-image", ] @@ -1903,6 +2095,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -1916,6 +2111,12 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -1940,6 +2141,30 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jiff" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "jni" version = "0.21.1" @@ -1951,7 +2176,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -2234,6 +2459,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.12" @@ -2351,6 +2582,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.1" @@ -2375,6 +2615,50 @@ dependencies = [ "paste", ] +[[package]] +name = "metal" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" +dependencies = [ + "bitflags 2.9.0", + "block", + "core-graphics-types 0.1.3", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "minifb" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1a093126f2ed9012fc0b146934c97eb0273e54983680a8bf5309b6b4a365b32" +dependencies = [ + "cc", + "console_error_panic_hook", + "dlib", + "futures", + "instant", + "js-sys", + "lazy_static", + "libc", + "orbclient", + "raw-window-handle", + "serde", + "serde_derive", + "tempfile", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-client 0.29.5", + "wayland-cursor 0.29.5", + "wayland-protocols 0.29.5", + "web-sys", + "winapi", + "x11-dl", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2403,7 +2687,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843" dependencies = [ - "bit-set", + "bit-set 0.5.3", "bitflags 2.9.0", "codespan-reporting", "hexf-parse", @@ -2413,7 +2697,29 @@ dependencies = [ "rustc-hash 1.1.0", "spirv", "termcolor", - "thiserror", + "thiserror 1.0.69", + "unicode-xid", +] + +[[package]] +name = "naga" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" +dependencies = [ + "arrayvec", + "bit-set 0.8.0", + "bitflags 2.9.0", + "cfg_aliases 0.2.1", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "rustc-hash 1.1.0", + "spirv", + "strum", + "termcolor", + "thiserror 2.0.12", "unicode-xid", ] @@ -2429,7 +2735,7 @@ dependencies = [ "ndk-sys 0.6.0+11769913", "num_enum", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2462,6 +2768,18 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + [[package]] name = "nix" version = "0.29.0" @@ -2472,7 +2790,7 @@ dependencies = [ "cfg-if", "cfg_aliases 0.2.1", "libc", - "memoffset", + "memoffset 0.9.1", ] [[package]] @@ -2832,7 +3150,19 @@ version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba0b26cec2e24f08ed8bb31519a9333140a6599b867dac464bb150bdb796fd43" dependencies = [ + "libc", "libredox", + "sdl2", + "sdl2-sys", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", ] [[package]] @@ -3107,6 +3437,27 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -3270,7 +3621,7 @@ dependencies = [ "rand_chacha", "simd_helpers", "system-deps", - "thiserror", + "thiserror 1.0.69", "v_frame", "wasm-bindgen", ] @@ -3361,7 +3712,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3528,6 +3879,29 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "sdl2" +version = "0.35.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a" +dependencies = [ + "bitflags 1.3.2", + "lazy_static", + "libc", + "sdl2-sys", +] + +[[package]] +name = "sdl2-sys" +version = "0.35.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0" +dependencies = [ + "cfg-if", + "libc", + "version-compare 0.1.1", +] + [[package]] name = "self_cell" version = "1.1.0" @@ -3700,14 +4074,14 @@ dependencies = [ "log", "memmap2", "rustix 0.38.44", - "thiserror", + "thiserror 1.0.69", "wayland-backend", - "wayland-client", + "wayland-client 0.31.8", "wayland-csd-frame", - "wayland-cursor", - "wayland-protocols", + "wayland-cursor 0.31.8", + "wayland-protocols 0.32.6", "wayland-protocols-wlr", - "wayland-scanner", + "wayland-scanner 0.31.6", "xkeysym", ] @@ -3756,8 +4130,8 @@ dependencies = [ "tiny-xlib", "wasm-bindgen", "wayland-backend", - "wayland-client", - "wayland-sys", + "wayland-client 0.31.8", + "wayland-sys 0.31.6", "web-sys", "windows-sys 0.59.0", "x11rb", @@ -3784,6 +4158,28 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.100", +] + [[package]] name = "svg_fmt" version = "0.4.4" @@ -3842,7 +4238,7 @@ dependencies = [ "heck", "pkg-config", "toml", - "version-compare", + "version-compare 0.2.0", ] [[package]] @@ -3888,7 +4284,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -3902,6 +4307,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -4118,7 +4534,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" dependencies = [ - "memoffset", + "memoffset 0.9.1", "tempfile", "winapi", ] @@ -4183,6 +4599,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "v_frame" version = "0.3.8" @@ -4200,6 +4622,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + [[package]] name = "version-compare" version = "0.2.0" @@ -4246,6 +4674,8 @@ dependencies = [ "cfg-if", "once_cell", "rustversion", + "serde", + "serde_json", "wasm-bindgen-macro", ] @@ -4334,7 +4764,23 @@ dependencies = [ "rustix 0.38.44", "scoped-tls", "smallvec", - "wayland-sys", + "wayland-sys 0.31.6", +] + +[[package]] +name = "wayland-client" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715" +dependencies = [ + "bitflags 1.3.2", + "downcast-rs", + "libc", + "nix 0.24.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner 0.29.5", + "wayland-sys 0.29.5", ] [[package]] @@ -4346,7 +4792,19 @@ dependencies = [ "bitflags 2.9.0", "rustix 0.38.44", "wayland-backend", - "wayland-scanner", + "wayland-scanner 0.31.6", +] + +[[package]] +name = "wayland-commons" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902" +dependencies = [ + "nix 0.24.3", + "once_cell", + "smallvec", + "wayland-sys 0.29.5", ] [[package]] @@ -4360,6 +4818,17 @@ dependencies = [ "wayland-backend", ] +[[package]] +name = "wayland-cursor" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661" +dependencies = [ + "nix 0.24.3", + "wayland-client 0.29.5", + "xcursor", +] + [[package]] name = "wayland-cursor" version = "0.31.8" @@ -4367,10 +4836,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a93029cbb6650748881a00e4922b076092a6a08c11e7fbdb923f064b23968c5d" dependencies = [ "rustix 0.38.44", - "wayland-client", + "wayland-client 0.31.8", "xcursor", ] +[[package]] +name = "wayland-protocols" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6" +dependencies = [ + "bitflags 1.3.2", + "wayland-client 0.29.5", + "wayland-commons", + "wayland-scanner 0.29.5", +] + [[package]] name = "wayland-protocols" version = "0.32.6" @@ -4379,8 +4860,8 @@ checksum = "0781cf46869b37e36928f7b432273c0995aa8aed9552c556fb18754420541efc" dependencies = [ "bitflags 2.9.0", "wayland-backend", - "wayland-client", - "wayland-scanner", + "wayland-client 0.31.8", + "wayland-scanner 0.31.6", ] [[package]] @@ -4391,9 +4872,9 @@ checksum = "7ccaacc76703fefd6763022ac565b590fcade92202492381c95b2edfdf7d46b3" dependencies = [ "bitflags 2.9.0", "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-scanner", + "wayland-client 0.31.8", + "wayland-protocols 0.32.6", + "wayland-scanner 0.31.6", ] [[package]] @@ -4404,9 +4885,20 @@ checksum = "248a02e6f595aad796561fa82d25601bd2c8c3b145b1c7453fc8f94c1a58f8b2" dependencies = [ "bitflags 2.9.0", "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-scanner", + "wayland-client 0.31.8", + "wayland-protocols 0.32.6", + "wayland-scanner 0.31.6", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", ] [[package]] @@ -4420,6 +4912,17 @@ dependencies = [ "quote", ] +[[package]] +name = "wayland-sys" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + [[package]] name = "wayland-sys" version = "0.31.6" @@ -4469,7 +4972,7 @@ dependencies = [ "cfg_aliases 0.1.1", "js-sys", "log", - "naga", + "naga 0.19.2", "parking_lot 0.12.3", "profiling", "raw-window-handle", @@ -4478,9 +4981,35 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "wgpu-core", - "wgpu-hal", - "wgpu-types", + "wgpu-core 0.19.4", + "wgpu-hal 0.19.5", + "wgpu-types 0.19.2", +] + +[[package]] +name = "wgpu" +version = "24.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35904fb00ba2d2e0a4d002fcbbb6e1b89b574d272a50e5fc95f6e81cf281c245" +dependencies = [ + "arrayvec", + "bitflags 2.9.0", + "cfg_aliases 0.2.1", + "document-features", + "js-sys", + "log", + "naga 24.0.0", + "parking_lot 0.12.3", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core 24.0.2", + "wgpu-hal 24.0.2", + "wgpu-types 24.0.0", ] [[package]] @@ -4490,23 +5019,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b94525fc99ba9e5c9a9e24764f2bc29bad0911a7446c12f446a8277369bf3a" dependencies = [ "arrayvec", - "bit-vec", + "bit-vec 0.6.3", "bitflags 2.9.0", "cfg_aliases 0.1.1", "codespan-reporting", "indexmap", "log", - "naga", + "naga 0.19.2", "once_cell", "parking_lot 0.12.3", "profiling", "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror", + "thiserror 1.0.69", "web-sys", - "wgpu-hal", - "wgpu-types", + "wgpu-hal 0.19.5", + "wgpu-types 0.19.2", +] + +[[package]] +name = "wgpu-core" +version = "24.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c25545d479b47d3f0a8e373aceb2060b67c6eb841b24ac8c32348151c7a0c" +dependencies = [ + "arrayvec", + "bit-vec 0.8.0", + "bitflags 2.9.0", + "cfg_aliases 0.2.1", + "document-features", + "indexmap", + "log", + "naga 24.0.0", + "once_cell", + "parking_lot 0.12.3", + "profiling", + "raw-window-handle", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.12", + "wgpu-hal 24.0.2", + "wgpu-types 24.0.0", ] [[package]] @@ -4517,26 +5071,26 @@ checksum = "bfabcfc55fd86611a855816326b2d54c3b2fd7972c27ce414291562650552703" dependencies = [ "android_system_properties", "arrayvec", - "ash", - "bit-set", + "ash 0.37.3+1.3.251", + "bit-set 0.5.3", "bitflags 2.9.0", "block", "cfg_aliases 0.1.1", "core-graphics-types 0.1.3", "d3d12", - "glow", - "glutin_wgl_sys", + "glow 0.13.1", + "glutin_wgl_sys 0.5.0", "gpu-alloc", - "gpu-allocator", - "gpu-descriptor", + "gpu-allocator 0.25.0", + "gpu-descriptor 0.2.4", "hassle-rs", "js-sys", "khronos-egl", "libc", "libloading 0.8.6", "log", - "metal", - "naga", + "metal 0.27.0", + "naga 0.19.2", "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", @@ -4547,13 +5101,59 @@ dependencies = [ "renderdoc-sys", "rustc-hash 1.1.0", "smallvec", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "web-sys", - "wgpu-types", + "wgpu-types 0.19.2", "winapi", ] +[[package]] +name = "wgpu-hal" +version = "24.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4317a17171dc20e6577bf606796794580accae0716a69edbc7388c86a3ec9f23" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash 0.38.0+1.3.281", + "bit-set 0.8.0", + "bitflags 2.9.0", + "block", + "bytemuck", + "cfg_aliases 0.2.1", + "core-graphics-types 0.1.3", + "glow 0.16.0", + "glutin_wgl_sys 0.6.1", + "gpu-alloc", + "gpu-allocator 0.27.0", + "gpu-descriptor 0.3.1", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.6", + "log", + "metal 0.31.0", + "naga 24.0.0", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "ordered-float", + "parking_lot 0.12.3", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.12", + "wasm-bindgen", + "web-sys", + "wgpu-types 24.0.0", + "windows 0.58.0", + "windows-core 0.58.0", +] + [[package]] name = "wgpu-types" version = "0.19.2" @@ -4565,6 +5165,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wgpu-types" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" +dependencies = [ + "bitflags 2.9.0", + "js-sys", + "log", + "web-sys", +] + [[package]] name = "widestring" version = "1.2.0" @@ -4613,7 +5225,7 @@ dependencies = [ "clipboard_wayland", "clipboard_x11", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4622,7 +5234,17 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", + "windows-core 0.52.0", + "windows-targets 0.52.6", +] + +[[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", ] @@ -4635,6 +5257,60 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[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.100", +] + +[[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.100", +] + +[[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-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -4881,8 +5557,8 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "wayland-backend", - "wayland-client", - "wayland-protocols", + "wayland-client 0.31.8", + "wayland-protocols 0.32.6", "wayland-protocols-plasma", "web-sys", "web-time", @@ -5020,7 +5696,7 @@ dependencies = [ "futures-sink", "futures-util", "hex", - "nix", + "nix 0.29.0", "ordered-stream", "rand", "serde", diff --git a/Cargo.toml b/Cargo.toml index 36ff2ad..5d9340b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,17 +4,33 @@ version = "0.1.0" edition = "2024" [dependencies] +env_logger = "0.11.7" iced = { version = "0.13.1", features = ["debug", "canvas", "tokio", "image"]} image = "0.25.6" itertools = "0.12" memmap2 = "0.9.5" +minifb = "0.28.0" +pollster = "0.4.0" # rustc-hash.workspace = true tokio = { version = "1.44.1", features = ["sync"] } tracing-subscriber = "0.3" +wgpu = "24.0.3" +winit = "0.30.9" zune-image = {version = "0.4.15", features = ["all"]} + [profile.dev.package.zune-jpeg] opt-level = 3 +[profile.release] +opt-level = 3 +debug = false +debug-assertions = false +overflow-checks = false +lto = false +panic = 'unwind' +incremental = false +codegen-units = 32 +rpath = false [dev-dependencies] criterion = "0.3" diff --git a/benches/image_load.rs b/benches/image_load.rs index 3cde65b..dcb67c7 100644 --- a/benches/image_load.rs +++ b/benches/image_load.rs @@ -1,17 +1,44 @@ #![allow(unused)] use std::iter; +use std::time::Duration; use criterion::BenchmarkId; use criterion::{Criterion, black_box, criterion_group, criterion_main}; -use imflow::image::{Approach, load_thumbnail}; -const PATH: &str = "test_images/20240811-194516_DSC02274.JPG"; +use imflow::image::{load_available_images, load_image_argb, load_image_argb_imagers, load_thumbnail, Approach}; +const PATH: &str = "test_images"; pub fn criterion_benchmark(c: &mut Criterion) { - let mut group = c.benchmark_group("from_elem"); - group.bench_function("mmap", |b| b.iter(|| load_thumbnail(PATH, Approach::Mmap))); - group.bench_function("path", |b| b.iter(|| load_thumbnail(PATH, Approach::Path))); - group.bench_function("iced", |b| b.iter(|| load_thumbnail(PATH, Approach::Iced))); + let mut group = c.benchmark_group("image_decode"); + + group + .sample_size(10) // Reduce number of samples (default is 100) + .measurement_time(Duration::from_millis(500)) // Reduce measurement time (default is 5 seconds) + .warm_up_time(Duration::from_millis(200)); // Reduce warm-up time (default is 3 seconds) + + let images = load_available_images(PATH.into()); + for image in images.iter() { + let image_name = image.to_str().unwrap(); + + // Benchmark zune for this image + group.bench_with_input( + format!("{}/zune", image_name), + image, + |b, image| { + b.iter(|| load_image_argb(image.clone().into())); + }, + ); + + // Benchmark image-rs for the same image + group.bench_with_input( + format!("{}/image-rs", image_name), + image, + |b, image| { + b.iter(|| load_image_argb_imagers(image.clone().into())); + }, + ); + } + group.finish(); } diff --git a/src/image.rs b/src/image.rs index dbaa325..b6f64b8 100644 --- a/src/image.rs +++ b/src/image.rs @@ -1,13 +1,28 @@ +use iced::widget::image::Handle; +use iced::widget::image::Image as IcedImage; +use image::DynamicImage; +use image::ImageReader; +use memmap2::Mmap; use zune_image::codecs::qoi::zune_core::options::DecoderOptions; +use zune_image::image::Image as ZuneImage; +use std::fs; use std::fs::File; +use std::io; +use std::io::Read; +use std::ops::Deref; +use std::path::PathBuf; +use std::time::Instant; pub enum Approach { Mmap, Path, + ImageRs, Iced, + ImageRsPath, } -fn convert_rgb_to_rgba(rgb_data: Vec>) -> Vec { + +pub fn convert_zune_rgb_to_rgba(rgb_data: Vec>) -> Vec { let r_channel = &rgb_data[0]; let num_pixels = r_channel.len() / 3; @@ -22,56 +37,206 @@ fn convert_rgb_to_rgba(rgb_data: Vec>) -> Vec { rgba_data } + +pub fn map_file(path: &str) -> io::Result { + let file = File::open(path)?; + unsafe { Mmap::map(&file) } +} + +pub fn map_file_path(path: PathBuf) -> io::Result { + let file = File::open(path)?; + unsafe { Mmap::map(&file) } +} + +pub fn read_zune_image(mmap: &[u8]) -> Result { + ZuneImage::read(mmap, DecoderOptions::new_fast()).map_err(|e| e.to_string()) +} + +pub fn read_zune_image_path(path: &str) -> ZuneImage { + zune_image::image::Image::open_with_options(path, DecoderOptions::new_fast()).unwrap() +} + +pub fn flatten_zune_image(img: &ZuneImage) -> Vec> { + img.flatten_to_u8() +} + +pub fn flatten_image_image(img: DynamicImage) -> Vec { + img.into_rgba8().into_raw() +} + +pub fn create_iced_handle(width: u32, height: u32, rgba: Vec) -> Handle { + Handle::from_rgba(width, height, rgba) +} + pub fn load_thumbnail( path: &str, approach: Approach, ) -> Result { match approach { Approach::Mmap => { - let file = File::open(path).map_err(|e| e.to_string())?; - let mmap = unsafe { memmap2::Mmap::map(&file) }.map_err(|e| e.to_string())?; + let mmap = map_file(path).unwrap(); println!("mapped file"); - let img = zune_image::image::Image::read(&*mmap, DecoderOptions::default()).unwrap(); + let img = read_zune_image(mmap.deref())?; let width = img.dimensions().0 as u32; let height = img.dimensions().1 as u32; println!("loaded"); - let flat = img.flatten_to_u8(); + let flat = flatten_zune_image(&img); println!("flattened"); - let rgba = convert_rgb_to_rgba(flat); + let rgba = convert_zune_rgb_to_rgba(flat); println!("rgbad"); - let conv = iced::widget::image::Handle::from_rgba(width, height, rgba); + let conv = create_iced_handle(width, height, rgba); println!("iced"); Ok(conv) } Approach::Path => { - let img = zune_image::image::Image::open_with_options(path, DecoderOptions::default()) - .unwrap(); + let img = read_zune_image_path(path); let width = img.dimensions().0 as u32; let height = img.dimensions().1 as u32; println!("loaded"); - let flat = img.flatten_to_u8(); + let flat = flatten_zune_image(&img); println!("flattened"); - let rgba = convert_rgb_to_rgba(flat); + let rgba = convert_zune_rgb_to_rgba(flat); println!("rgbad"); - let conv = iced::widget::image::Handle::from_rgba(width, height, rgba); + let conv = create_iced_handle(width, height, rgba); println!("iced"); Ok(conv) } - Approach::Iced => { - let file = File::open(path).map_err(|e| e.to_string())?; - let mmap = unsafe { memmap2::Mmap::map(&file) }.map_err(|e| e.to_string())?; - let img = image::load_from_memory(&mmap).map_err(|e| e.to_string())?; + Approach::ImageRs => { + let mmap = map_file(path).unwrap(); + let img = image::load_from_memory(mmap.deref()).map_err(|e| e.to_string())?; let width = img.width(); let height = img.height(); println!("loaded"); - let rgba = img.into_rgba8().into_raw(); + let rgba = flatten_image_image(img); println!("rgbad"); - let conv = iced::widget::image::Handle::from_rgba(width, height, rgba); + let conv = create_iced_handle(width, height, rgba); println!("iced"); Ok(conv) } + Approach::ImageRsPath => { + let img = ImageReader::open(path).unwrap().decode().unwrap(); + let width = img.width(); + let height = img.height(); + println!("loaded"); + let rgba = flatten_image_image(img); + println!("rgbad"); + let conv = create_iced_handle(width, height, rgba); + println!("iced"); + + Ok(conv) + } + Approach::Iced => Ok(Handle::from_path(path)), } } + +pub fn load_image_argb(path: PathBuf) -> ImflowImageBuffer { + let total_start = Instant::now(); + + // Stage 1: Memory map the file + let stage1_start = Instant::now(); + let mmap = map_file_path(path).unwrap(); + let stage1_time = stage1_start.elapsed(); + println!("File mapping took: {:?}", stage1_time); + + // Stage 2: Read the image + let stage2_start = Instant::now(); + let img = read_zune_image(mmap.deref()).unwrap(); + let width = img.dimensions().0; + let height = img.dimensions().1; + let stage2_time = stage2_start.elapsed(); + println!("Image decoding took: {:?}", stage2_time); + + // Stage 3: Flatten the image + let stage3_start = Instant::now(); + let flat = &mut flatten_zune_image(&img)[0]; + let stage3_time = stage3_start.elapsed(); + println!("Image flattening took: {:?}", stage3_time); + + // Stage 4: Convert to ARGB format + let stage4_start = Instant::now(); + let mut buffer: Vec = vec![0; width * height]; + + for (rgba, argb) in flat.chunks_mut(3).zip(buffer.iter_mut()) { + let r = rgba[0] as u32; + let g = rgba[1] as u32; + let b = rgba[2] as u32; + *argb = r << 16 | g << 8 | b; + } + let stage4_time = stage4_start.elapsed(); + println!("RGBA to ARGB conversion took: {:?}", stage4_time); + + // Total time + let total_time = total_start.elapsed(); + println!("Total loading time: {:?}", total_time); + + ImflowImageBuffer { + width, + height, + argb_buffer: buffer, + } +} + +pub struct ImflowImageBuffer { + pub width: usize, + pub height: usize, + pub argb_buffer: Vec, +} + +pub fn load_image_argb_imagers(path: PathBuf) -> ImflowImageBuffer { + let total_start = Instant::now(); + + // Stage 1: Memory map the file + let stage1_start = Instant::now(); + let mmap = map_file_path(path).unwrap(); + let stage1_time = stage1_start.elapsed(); + println!("File mapping took: {:?}", stage1_time); + + // Stage 2: Read the image + let stage2_start = Instant::now(); + let img = image::load_from_memory(mmap.deref()).map_err(|e| e.to_string()).unwrap(); + let width = img.width() as usize; + let height = img.height() as usize; + let stage2_time = stage2_start.elapsed(); + println!("Image decoding took: {:?}", stage2_time); + + // Stage 3: Flatten the image + let stage3_start = Instant::now(); + let mut flat = img.into_rgba8().into_raw(); + let stage3_time = stage3_start.elapsed(); + println!("Image flattening took: {:?}", stage3_time); + + // Stage 4: Convert to ARGB format + let stage4_start = Instant::now(); + let mut buffer: Vec = vec![0; width * height]; + + for (rgba, argb) in flat.chunks_mut(4).zip(buffer.iter_mut()) { + let r = rgba[0] as u32; + let g = rgba[1] as u32; + let b = rgba[2] as u32; + *argb = r << 16 | g << 8 | b; + } + let stage4_time = stage4_start.elapsed(); + println!("RGBA to ARGB conversion took: {:?}", stage4_time); + + // Total time + let total_time = total_start.elapsed(); + println!("Total loading time: {:?}", total_time); + + ImflowImageBuffer { + width, + height, + argb_buffer: buffer, + } +} +pub fn load_available_images(dir: PathBuf) -> Vec { + let mut files: Vec = fs::read_dir(dir) + .unwrap() + .map(|f| f.unwrap().path()) + .collect(); + files.sort(); + files +} + diff --git a/src/main.rs b/src/main.rs index 4bbd952..2692906 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,9 @@ use std::collections::HashMap; use std::fs::{self}; use std::io::Read; +use std::ops::Deref; use std::path::{Path, PathBuf}; -use std::time::{self, Duration}; +use std::time::{self, Duration, Instant}; use iced::futures::AsyncReadExt; use iced::widget::shader::wgpu::core::command::LoadOp; @@ -16,22 +17,391 @@ use iced::widget::{ Column, Container, button, center, checkbox, column, container, pick_list, row, slider, text, }; use iced::{Center, Element, Fill, Length, Size, Subscription, Task, Theme, keyboard}; -use image::{self, DynamicImage, EncodableLayout, ImageBuffer, ImageReader}; +use image::{self, DynamicImage, EncodableLayout, GenericImageView, ImageBuffer, ImageReader}; -use imflow::image::{Approach, load_thumbnail}; +use imflow::image::{ + flatten_image_image, flatten_zune_image, load_available_images, load_image_argb, load_image_argb_imagers, load_thumbnail, map_file, map_file_path, read_zune_image, Approach, ImflowImageBuffer +}; +use minifb::{Key, Window, WindowOptions}; use zune_image::codecs::qoi::zune_core::options::DecoderOptions; // for general image operations // use image::io::Reader as ImageReader; // specifically for Reader -pub fn main() -> iced::Result { - tracing_subscriber::fmt::init(); +use std::sync::Arc; - iced::application("Game of Life - Iced", GameOfLife::update, GameOfLife::view) - .subscription(GameOfLife::subscription) - .theme(|_| Theme::Dark) - .antialiasing(true) - .centered() - .window_size(Size::new(1500.0, 1000.0)) - .run() +// use winit::{ +// application::ApplicationHandler, +// event::WindowEvent, +// event_loop::{ActiveEventLoop, ControlFlow, EventLoop}, +// window::{Window, WindowId}, +// }; +// struct State { +// window: Arc, +// device: wgpu::Device, +// queue: wgpu::Queue, +// size: winit::dpi::PhysicalSize, +// surface: wgpu::Surface<'static>, +// surface_format: wgpu::TextureFormat, +// } + +// impl State { +// async fn new(window: Arc) -> State { +// let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default()); +// let adapter = instance +// .request_adapter(&wgpu::RequestAdapterOptions::default()) +// .await +// .unwrap(); +// let (device, queue) = adapter +// .request_device(&wgpu::DeviceDescriptor::default(), None) +// .await +// .unwrap(); + +// let size = window.inner_size(); + +// let surface = instance.create_surface(window.clone()).unwrap(); +// let cap = surface.get_capabilities(&adapter); +// let surface_format = cap.formats[0]; + +// let state = State { +// window, +// device, +// queue, +// size, +// surface, +// surface_format, +// }; + +// // Configure surface for the first time +// state.configure_surface(); + +// state +// } + +// fn get_window(&self) -> &Window { +// &self.window +// } + +// fn configure_surface(&self) { +// let surface_config = wgpu::SurfaceConfiguration { +// usage: wgpu::TextureUsages::RENDER_ATTACHMENT, +// format: self.surface_format, +// // Request compatibility with the sRGB-format texture view we‘re going to create later. +// view_formats: vec![self.surface_format.add_srgb_suffix()], +// alpha_mode: wgpu::CompositeAlphaMode::Auto, +// width: self.size.width, +// height: self.size.height, +// desired_maximum_frame_latency: 2, +// present_mode: wgpu::PresentMode::AutoVsync, +// }; +// self.surface.configure(&self.device, &surface_config); +// } + +// fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { +// self.size = new_size; + +// // reconfigure the surface +// self.configure_surface(); +// } + +// // fn render(&mut self) { +// // // Create texture view +// // let surface_texture = self +// // .surface +// // .get_current_texture() +// // .expect("failed to acquire next swapchain texture"); +// // let texture_view = surface_texture +// // .texture +// // .create_view(&wgpu::TextureViewDescriptor { +// // // Without add_srgb_suffix() the image we will be working with +// // // might not be "gamma correct". +// // format: Some(self.surface_format.add_srgb_suffix()), +// // ..Default::default() +// // }); + +// // // Renders a GREEN screen +// // let mut encoder = self.device.create_command_encoder(&Default::default()); +// // // Create the renderpass which will clear the screen. +// // let renderpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { +// // label: None, +// // color_attachments: &[Some(wgpu::RenderPassColorAttachment { +// // view: &texture_view, +// // resolve_target: None, +// // ops: wgpu::Operations { +// // load: wgpu::LoadOp::Clear(wgpu::Color::GREEN), +// // store: wgpu::StoreOp::Store, +// // }, +// // })], +// // depth_stencil_attachment: None, +// // timestamp_writes: None, +// // occlusion_query_set: None, +// // }); + +// // // If you wanted to call any drawing commands, they would go here. + +// // // End the renderpass. +// // drop(renderpass); + +// // // Submit the command in the queue to execute +// // self.queue.submit([encoder.finish()]); +// // self.window.pre_present_notify(); +// // surface_texture.present(); +// // } + +// fn render(&mut self) { +// let mmap = map_file("test_images/20240811-194516_DSC02274.JPG").unwrap(); +// println!("mapped file"); +// let img = read_zune_image(mmap.deref()).unwrap(); +// let width = img.dimensions().0 as u32; +// let height = img.dimensions().1 as u32; +// println!("loaded"); +// let flat = flatten_zune_image(&img); +// println!("flattened"); + +// let rgb_bytes = flat[0].as_slice(); +// // Assuming `self.rgb_bytes` is your buffer containing RGB data. +// let texture_extent = wgpu::Extent3d { +// width: width, +// height: height, +// depth_or_array_layers: 1, +// }; + +// // Create a wgpu texture +// let texture = self.device.create_texture(&wgpu::TextureDescriptor { +// label: Some("RGB Texture"), +// size: texture_extent, +// mip_level_count: 1, +// sample_count: 1, +// dimension: wgpu::TextureDimension::D2, +// format: wgpu::TextureFormat::Rgba8Unorm, // It's better to use RGBA with proper padding +// usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, +// view_formats: &[], +// }); + +// // Upload your RGB data into the texture +// self.queue.write_texture( +// wgpu::TexelCopyTextureInfo{ +// texture: &texture, +// mip_level: 0, +// origin: wgpu::Origin3d::ZERO, +// aspect: wgpu::TextureAspect::All, +// }, +// &rgb_bytes, +// wgpu::TexelCopyBufferLayout { +// offset: 0, +// bytes_per_row: Some(4 * width), // Assuming padded row length +// rows_per_image: Some(height), +// }, +// texture_extent, +// ); + +// // Create a texture view +// let surface_texture = self +// .surface +// .get_current_texture() +// .expect("failed to acquire next swapchain texture"); + +// let texture_view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor { +// format: Some(self.surface_format.add_srgb_suffix()), +// ..Default::default() +// }); + +// let rgb_texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + +// let mut encoder = self.device.create_command_encoder(&Default::default()); + +// // Create the renderpass +// let mut renderpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { +// label: None, +// color_attachments: &[Some(wgpu::RenderPassColorAttachment { +// view: &texture_view, +// resolve_target: None, +// ops: wgpu::Operations { +// load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), +// store: wgpu::StoreOp::Store, +// }, +// })], +// depth_stencil_attachment: None, +// timestamp_writes: None, +// occlusion_query_set: None, +// }); + +// // Bind and draw +// // renderpass.set_pipeline(&self.pipeline); // Ensure self.pipeline is your render pipeline setup +// // renderpass.set_bind_group(0, &self.texture_bind_group, &[]); // Assuming you have a bind group which holds the texture +// renderpass.draw(0..3, 0..1); // Draws a triangle to cover the viewport, modify as needed for quads + +// // End the renderpass +// drop(renderpass); + +// // Submit the command buffer +// // self.queue.submit(iter::once(encoder.finish())); +// self.window.pre_present_notify(); +// surface_texture.present(); +// } +// } + +// #[derive(Default)] +// struct App { +// state: Option, +// } + +// impl ApplicationHandler for App { +// fn resumed(&mut self, event_loop: &ActiveEventLoop) { +// // Create window object +// let window = Arc::new( +// event_loop +// .create_window(Window::default_attributes()) +// .unwrap(), +// ); + +// let state = pollster::block_on(State::new(window.clone())); +// self.state = Some(state); + +// window.request_redraw(); +// } + +// fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { +// let state = self.state.as_mut().unwrap(); +// match event { +// WindowEvent::CloseRequested => { +// println!("The close button was pressed; stopping"); +// event_loop.exit(); +// } +// WindowEvent::RedrawRequested => { +// state.render(); +// // Emits a new redraw requested event. +// state.get_window().request_redraw(); +// } +// WindowEvent::Resized(size) => { +// // Reconfigures the size of the surface. We do not re-render +// // here as this event is always followed up by redraw request. +// state.resize(size); +// } +// _ => (), +// } +// } +// } +// pub fn main() -> iced::Result { +// tracing_subscriber::fmt::init(); + +// iced::application("Game of Life - Iced", GameOfLife::update, GameOfLife::view) +// .subscription(GameOfLife::subscription) +// .theme(|_| Theme::Dark) +// .antialiasing(true) +// .centered() +// .window_size(Size::new(1500.0, 1000.0)) +// .run() +// } + +// fn main() { +// let mut window = match Window::new("Test", 640, 400, WindowOptions::default()) { +// Ok(win) => win, +// Err(err) => { +// println!("Unable to create window {}", err); +// return; +// } +// } +// } + +// fn main() { +// // wgpu uses `log` for all of our logging, so we initialize a logger with the `env_logger` crate. +// // +// // To change the log level, set the `RUST_LOG` environment variable. See the `env_logger` +// // documentation for more information. +// env_logger::init(); + +// let event_loop = EventLoop::new().unwrap(); + +// // When the current loop iteration finishes, immediately begin a new +// // iteration regardless of whether or not new events are available to +// // process. Preferred for applications that want to render as fast as +// // possible, like games. +// event_loop.set_control_flow(ControlFlow::Poll); + +// // When the current loop iteration finishes, suspend the thread until +// // another event arrives. Helps keeping CPU utilization low if nothing +// // is happening, which is preferred if the application might be idling in +// // the background. +// // event_loop.set_control_flow(ControlFlow::Wait); + +// let mut app = App::default(); +// event_loop.run_app(&mut app).unwrap(); +// } +// + +struct State { + current_image_id: usize, + loaded_images: HashMap, + available_images: Vec, + current_image_path: PathBuf, +} + +impl State { + fn new() -> Self { + let current_image_id: usize = 0; + let mut loaded_images: HashMap = HashMap::new(); + let available_images = load_available_images("./test_images".into()); + let new_path = available_images[0].clone(); + let current_image = load_image_argb_imagers(new_path.clone()); + loaded_images.insert(new_path.clone(), current_image); + Self { + current_image_id, + loaded_images, + available_images, + current_image_path: new_path, + } + } + + fn next_image(&mut self, change: i32) { + self.current_image_id = (self.current_image_id as i32 + change) + .clamp(0, self.available_images.len() as i32 - 1) + as usize; + let new_path = self.available_images[self.current_image_id].clone(); + if !self.loaded_images.contains_key(&new_path) { + let new_image = load_image_argb(new_path.clone()); + self.loaded_images.insert(new_path.clone(), new_image); + } + self.current_image_path = new_path; + } + + fn get_current_image(&self) -> &ImflowImageBuffer { + self.loaded_images.get(&self.current_image_path).unwrap() + } +} + +fn main() { + const WIDTH: usize = 1920; + const HEIGHT: usize = 1080; + let mut window = Window::new( + "Test - ESC to exit", + WIDTH, + HEIGHT, + WindowOptions::default(), + ) + .unwrap_or_else(|e| { + panic!("{}", e); + }); + + window.set_target_fps(60); + + let mut state = State::new(); + show_image(&mut window, state.get_current_image()); + + while window.is_open() && !window.is_key_down(Key::Escape) { + window.update(); + if window.is_key_down(Key::Right) { + state.next_image(1); + show_image(&mut window, state.get_current_image()); + } else if window.is_key_down(Key::Left) { + state.next_image(-1); + show_image(&mut window, state.get_current_image()); + } + } +} + +fn show_image(window: &mut Window, image: &ImflowImageBuffer) { + window + .update_with_buffer(&image.argb_buffer, image.width, image.height) + .unwrap(); } struct GameOfLife { @@ -145,7 +515,7 @@ impl GameOfLife { if !self.loaded_images.contains_key(&path.to_path_buf()) { self.loaded_images.insert( path.to_path_buf(), - load_thumbnail(path.to_str().unwrap(), Approach::Iced).unwrap(), + load_thumbnail(path.to_str().unwrap(), Approach::ImageRs).unwrap(), ); } }