aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dhwt-codec/.gitignore2
-rw-r--r--dhwt-codec/Cargo.lock350
-rw-r--r--dhwt-codec/Cargo.toml9
-rwxr-xr-xdhwt-codec/run16
-rw-r--r--dhwt-codec/src/bin/decode.rs54
-rw-r--r--dhwt-codec/src/bin/encode.rs54
-rw-r--r--dhwt-codec/src/bin/export.rs42
-rw-r--r--dhwt-codec/src/bin/import.rs51
-rw-r--r--dhwt-codec/src/io.rs71
-rw-r--r--dhwt-codec/src/lib.rs23
-rw-r--r--dhwt-codec/src/transform.rs42
-rw-r--r--dhwt-codec/src/trim.rs36
-rw-r--r--dhwt-codec/src/view.rs42
-rw-r--r--vgcodec/.gitignore3
-rw-r--r--vgcodec/Cargo.lock1310
-rw-r--r--vgcodec/Cargo.toml13
-rw-r--r--vgcodec/src/app.rs37
-rw-r--r--vgcodec/src/diff.rs120
-rw-r--r--vgcodec/src/diff.wgsl17
-rw-r--r--vgcodec/src/export.rs80
-rw-r--r--vgcodec/src/main.rs76
-rw-r--r--vgcodec/src/paint.rs120
-rw-r--r--vgcodec/src/paint.wgsl19
23 files changed, 2587 insertions, 0 deletions
diff --git a/dhwt-codec/.gitignore b/dhwt-codec/.gitignore
new file mode 100644
index 0000000..495c6ed
--- /dev/null
+++ b/dhwt-codec/.gitignore
@@ -0,0 +1,2 @@
+/target
+/a
diff --git a/dhwt-codec/Cargo.lock b/dhwt-codec/Cargo.lock
new file mode 100644
index 0000000..715ba3e
--- /dev/null
+++ b/dhwt-codec/Cargo.lock
@@ -0,0 +1,350 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bincode"
+version = "2.0.0-rc.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7bb50c5a2ef4b9b1e7ae73e3a73b52ea24b20312d629f9c4df28260b7ad2c3c4"
+dependencies = [
+ "bincode_derive",
+ "serde",
+]
+
+[[package]]
+name = "bincode_derive"
+version = "2.0.0-rc.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a45a23389446d2dd25dc8e73a7a3b3c43522b630cac068927f0649d43d719d2"
+dependencies = [
+ "virtue",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "4.0.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e"
+dependencies = [
+ "atty",
+ "bitflags",
+ "clap_derive",
+ "clap_lex",
+ "once_cell",
+ "strsim",
+ "termcolor",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
+dependencies = [
+ "cfg-if",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bf8df95e795db1a4aca2957ad884a2df35413b24bbeb3114422f3cc21498e8"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "crossbeam-utils",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "422f23e724af1240ec469ea1e834d87a4b59ce2efe2c6a96256b0c47e2fd86aa"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "dhwt-codec"
+version = "0.1.0"
+dependencies = [
+ "bincode",
+ "clap",
+ "rayon",
+]
+
+[[package]]
+name = "either"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+
+[[package]]
+name = "heck"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.137"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+
+[[package]]
+name = "memoffset"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+
+[[package]]
+name = "os_str_bytes"
+version = "6.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e"
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rayon"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
+dependencies = [
+ "crossbeam-deque",
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-utils",
+ "num_cpus",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "serde"
+version = "1.0.147"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "syn"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "virtue"
+version = "0.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b60dcd6a64dd45abf9bd426970c9843726da7fc08f44cd6fcebf68c21220a63"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/dhwt-codec/Cargo.toml b/dhwt-codec/Cargo.toml
new file mode 100644
index 0000000..080fe20
--- /dev/null
+++ b/dhwt-codec/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "dhwt-codec"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+bincode = "2.0.0-rc.2"
+clap = { version = "4.0.26", features = ["derive"] }
+rayon = "1.6.0"
diff --git a/dhwt-codec/run b/dhwt-codec/run
new file mode 100755
index 0000000..9f7013e
--- /dev/null
+++ b/dhwt-codec/run
@@ -0,0 +1,16 @@
+#!/bin/fish
+
+set f $argv[1]
+set x $argv[2]
+set y $argv[3]
+set z $argv[4]
+
+# cat /dev/urandom | cargo run --release --bin import -- -x $x -y $y -z $z a/inp
+ffmpeg -i $f -frames:v $z -filter_complex [0]scale={$x}x{$y},format=rgb24 -f rawvideo pipe:1 | cargo run --release --bin import -- -x $x -y $y -z $z a/inp
+
+time cargo run --release --bin encode -- -x $x -y $y -z $z a/inp a/enc
+time cargo run --release --bin decode -- -x $x -y $y -z $z a/enc a/out
+
+cargo run --release --bin export -- -x (math $x / 2) -y (math $y / 2) -z (math $z / 2) a/enc | ffmpeg -y -pixel_format rgb24 -f rawvideo -video_size (math $x / 2)x(math $y / 2) -i pipe:0 a/enc.webm
+cargo run --release --bin export -- -x $x -y $y -z $z a/out | ffmpeg -y -pixel_format rgb24 -f rawvideo -video_size {$x}x{$y} -i pipe:0 a/out.webm
+# cargo run --release --bin export -- -x $x -y $y -z $z a/raw_out | ffplay -pixel_format rgb24 -f rawvideo -video_size {$x}x{$y} pipe:0
diff --git a/dhwt-codec/src/bin/decode.rs b/dhwt-codec/src/bin/decode.rs
new file mode 100644
index 0000000..35881fc
--- /dev/null
+++ b/dhwt-codec/src/bin/decode.rs
@@ -0,0 +1,54 @@
+use clap::Parser;
+use dhwt_codec::{
+ io::{empty_videobuf, infile, outfile, read_videobuf_small, write_videobuf, VideoBuf},
+ transform, trim,
+ view::{BufferView, IndexMode},
+ CommonArgs,
+};
+use rayon::prelude::{IntoParallelIterator, ParallelIterator};
+
+fn main() {
+ let args = CommonArgs::parse();
+
+ let mut inf = infile(&args.infile);
+ let mut of = outfile(&args.outfile);
+
+ for c in 0..args.channels {
+ eprintln!("encoding channel #{c}");
+ let a = empty_videobuf(args.x, args.y, args.z);
+ let b = read_videobuf_small(&mut inf);
+
+ eprintln!("\tdecoding Z");
+ (0..args.x).into_par_iter().for_each(|x| {
+ for y in 0..args.y {
+ run_mode(make_mut(&b), make_mut(&a), IndexMode::XY(x, y), args.z)
+ }
+ });
+ eprintln!("\tdecoding Y");
+ (0..args.x).into_par_iter().for_each(|x| {
+ for z in 0..args.z {
+ run_mode(make_mut(&a), make_mut(&b), IndexMode::XZ(x, z), args.y)
+ }
+ });
+ eprintln!("\tdecoding X");
+ (0..args.y).into_par_iter().for_each(|y| {
+ for z in 0..args.z {
+ run_mode(make_mut(&b), make_mut(&a), IndexMode::YZ(y, z), args.x)
+ }
+ });
+ write_videobuf(&mut of, a);
+ }
+}
+
+fn run_mode(a: &mut VideoBuf, b: &mut VideoBuf, mode: IndexMode, size: usize) {
+ trim::untrim(size, &mut BufferView::new(b, mode));
+ transform::decode(
+ size,
+ &mut BufferView::new(a, mode),
+ &mut BufferView::new(b, mode),
+ );
+}
+
+fn make_mut<T>(r: &T) -> &mut T {
+ unsafe { &mut *((r as *const T) as *mut T) }
+}
diff --git a/dhwt-codec/src/bin/encode.rs b/dhwt-codec/src/bin/encode.rs
new file mode 100644
index 0000000..0e711b0
--- /dev/null
+++ b/dhwt-codec/src/bin/encode.rs
@@ -0,0 +1,54 @@
+use clap::Parser;
+use dhwt_codec::{
+ io::{empty_videobuf, infile, outfile, read_videobuf, write_videobuf_small, VideoBuf},
+ transform, trim,
+ view::{BufferView, IndexMode},
+ CommonArgs,
+};
+use rayon::prelude::{IntoParallelIterator, ParallelIterator};
+
+fn main() {
+ let args = CommonArgs::parse();
+
+ let mut inf = infile(&args.infile);
+ let mut of = outfile(&args.outfile);
+
+ for c in 0..args.channels {
+ eprintln!("encoding channel #{c}");
+ let o = empty_videobuf(args.x, args.y, args.z);
+ let i = read_videobuf(&mut inf);
+
+ eprintln!("\tencoding X");
+ (0..args.y).into_par_iter().for_each(|y| {
+ for z in 0..args.z {
+ run_mode(make_mut(&i), make_mut(&o), IndexMode::YZ(y, z), args.x)
+ }
+ });
+ eprintln!("\tencoding Y");
+ (0..args.x).into_par_iter().for_each(|x| {
+ for z in 0..args.z {
+ run_mode(make_mut(&o), make_mut(&i), IndexMode::XZ(x, z), args.y)
+ }
+ });
+ eprintln!("\tencoding Z");
+ (0..args.x).into_par_iter().for_each(|x| {
+ for y in 0..args.y {
+ run_mode(make_mut(&i), make_mut(&o), IndexMode::XY(x, y), args.z)
+ }
+ });
+ write_videobuf_small(&mut of, o);
+ }
+}
+
+fn run_mode(a: &mut VideoBuf, b: &mut VideoBuf, mode: IndexMode, size: usize) {
+ transform::encode(
+ size,
+ &mut BufferView::new(a, mode),
+ &mut BufferView::new(b, mode),
+ );
+ trim::trim(size, &mut BufferView::new(b, mode));
+}
+
+fn make_mut<T>(r: &T) -> &mut T {
+ unsafe { &mut *((r as *const T) as *mut T) }
+}
diff --git a/dhwt-codec/src/bin/export.rs b/dhwt-codec/src/bin/export.rs
new file mode 100644
index 0000000..73f3067
--- /dev/null
+++ b/dhwt-codec/src/bin/export.rs
@@ -0,0 +1,42 @@
+use clap::Parser;
+use dhwt_codec::io::{infile, read_videobuf};
+use std::io::{stdout, BufWriter, Write};
+
+#[derive(Parser)]
+#[clap(about)]
+struct ExportArgs {
+ #[arg(short)]
+ x: usize,
+ #[arg(short)]
+ y: usize,
+ #[arg(short)]
+ z: usize,
+
+ #[arg(short, long, default_value = "3")]
+ channels: usize,
+
+ infile: String,
+}
+
+fn main() {
+ let args = ExportArgs::parse();
+
+ let mut i = infile(&args.infile);
+ let mut writer = BufWriter::new(stdout());
+
+ let mut channels = vec![];
+ for _ in 0..args.channels {
+ channels.push(read_videobuf(&mut i))
+ }
+
+ for z in 0..args.z {
+ for y in 0..args.y {
+ for x in 0..args.x {
+ for c in 0..args.channels {
+ writer.write_all(&[channels[c][x][y][z] as u8]).unwrap();
+ }
+ }
+ }
+ }
+ writer.flush().unwrap();
+}
diff --git a/dhwt-codec/src/bin/import.rs b/dhwt-codec/src/bin/import.rs
new file mode 100644
index 0000000..cd2a35e
--- /dev/null
+++ b/dhwt-codec/src/bin/import.rs
@@ -0,0 +1,51 @@
+use clap::Parser;
+use dhwt_codec::io::{outfile, write_videobuf, Value};
+use std::io::{stdin, Read};
+
+#[derive(Parser)]
+#[clap(about)]
+struct ImportArgs {
+ #[arg(short)]
+ x: usize,
+ #[arg(short)]
+ y: usize,
+ #[arg(short)]
+ z: usize,
+
+ #[arg(short, long, default_value = "3")]
+ channels: usize,
+
+ outfile: String,
+}
+
+fn main() {
+ let args = ImportArgs::parse();
+
+ let mut rawbuf = (0..(args.x * args.y * args.z * args.channels))
+ .map(|_| 0u8)
+ .collect::<Vec<_>>();
+ stdin().read_exact(&mut rawbuf).unwrap();
+
+ let mut o = outfile(&args.outfile);
+
+ for c in 0..args.channels {
+ let mut cols = vec![];
+ for x in 0..args.x {
+ let mut col = vec![];
+ for y in 0..args.y {
+ let mut span = vec![];
+ for z in 0..args.z {
+ span.push(
+ rawbuf[c
+ + (x * args.channels)
+ + (y * args.channels * args.x)
+ + (z * args.channels * args.x * args.y)] as Value,
+ );
+ }
+ col.push(span);
+ }
+ cols.push(col)
+ }
+ write_videobuf(&mut o, cols)
+ }
+}
diff --git a/dhwt-codec/src/io.rs b/dhwt-codec/src/io.rs
new file mode 100644
index 0000000..c60bc79
--- /dev/null
+++ b/dhwt-codec/src/io.rs
@@ -0,0 +1,71 @@
+use bincode::config;
+use std::{
+ fs::File,
+ io::{BufReader, BufWriter, Read, Write},
+};
+
+pub type Value = f32;
+pub type VideoBuf = Vec<Vec<Vec<Value>>>;
+pub const ZERO: Value = 0 as Value;
+pub const TWO: Value = 2 as Value;
+
+pub fn empty_videobuf(x: usize, y: usize, z: usize) -> VideoBuf {
+ (0..x)
+ .map(|_| (0..y).map(|_| (0..z).map(|_| ZERO).collect()).collect())
+ .collect()
+}
+
+pub fn outfile(p: &str) -> impl Write {
+ BufWriter::new(File::create(p).unwrap())
+}
+pub fn infile(p: &str) -> impl Read {
+ BufReader::new(File::open(p).unwrap())
+}
+
+pub fn read_videobuf(f: &mut impl Read) -> VideoBuf {
+ bincode::decode_from_std_read(f, config::standard()).unwrap()
+}
+pub fn write_videobuf(f: &mut impl Write, i: VideoBuf) {
+ bincode::encode_into_std_write(i, f, config::standard()).unwrap();
+}
+
+pub fn write_videobuf_small(f: &mut impl Write, mut i: VideoBuf) {
+ for _ in 0..(i.len() / 2) {
+ i.pop();
+ }
+ for i in &mut i {
+ for _ in 0..(i.len() / 2) {
+ i.pop();
+ }
+ for i in i {
+ for _ in 0..(i.len() / 2) {
+ i.pop();
+ }
+ }
+ }
+ write_videobuf(f, i);
+}
+pub fn read_videobuf_small(f: &mut impl Read) -> VideoBuf {
+ let mut i = read_videobuf(f);
+
+ for i in &mut i {
+ for i in i {
+ for _ in 0..i.len() {
+ i.push(ZERO);
+ }
+ }
+ }
+ for i in &mut i {
+ for _ in 0..i.len() {
+ i.push((0..i[0].len()).map(|_| ZERO).collect());
+ }
+ }
+ for _ in 0..i.len() {
+ i.push(
+ (0..i[0].len())
+ .map(|_| ((0..i[0][0].len()).map(|_| ZERO)).collect())
+ .collect(),
+ );
+ }
+ i
+}
diff --git a/dhwt-codec/src/lib.rs b/dhwt-codec/src/lib.rs
new file mode 100644
index 0000000..69d6b4c
--- /dev/null
+++ b/dhwt-codec/src/lib.rs
@@ -0,0 +1,23 @@
+use clap::Parser;
+
+pub mod io;
+pub mod transform;
+pub mod trim;
+pub mod view;
+
+#[derive(Parser)]
+#[clap(about)]
+pub struct CommonArgs {
+ #[arg(short)]
+ pub x: usize,
+ #[arg(short)]
+ pub y: usize,
+ #[arg(short)]
+ pub z: usize,
+
+ #[arg(short, long, default_value = "3")]
+ pub channels: usize,
+
+ pub infile: String,
+ pub outfile: String,
+}
diff --git a/dhwt-codec/src/transform.rs b/dhwt-codec/src/transform.rs
new file mode 100644
index 0000000..82bccd1
--- /dev/null
+++ b/dhwt-codec/src/transform.rs
@@ -0,0 +1,42 @@
+use crate::io::{Value, TWO};
+use std::ops::{Index, IndexMut};
+
+pub fn encode<X: Index<usize, Output = Value> + IndexMut<usize, Output = Value>>(
+ size: usize,
+ a: &mut X,
+ b: &mut X,
+) {
+ let mut k = size;
+ while k != 1 {
+ k /= 2;
+ for i in 0..k {
+ let x = a[i * 2];
+ let y = a[i * 2 + 1];
+ b[i] = x + y;
+ b[k + i] = x - y;
+ }
+ for i in 0..k {
+ a[i] = b[i]
+ }
+ }
+}
+
+pub fn decode<X: Index<usize, Output = Value> + IndexMut<usize, Output = Value>>(
+ size: usize,
+ a: &mut X,
+ b: &mut X,
+) {
+ let mut k = 1;
+ while k != size {
+ for i in 0..k {
+ let avr = a[i] / TWO;
+ let spread = a[i + k] / TWO;
+ b[i * 2] = avr + spread;
+ b[i * 2 + 1] = avr - spread;
+ }
+ k *= 2;
+ for i in 0..k {
+ a[i] = b[i]
+ }
+ }
+}
diff --git a/dhwt-codec/src/trim.rs b/dhwt-codec/src/trim.rs
new file mode 100644
index 0000000..85a920a
--- /dev/null
+++ b/dhwt-codec/src/trim.rs
@@ -0,0 +1,36 @@
+use crate::io::{Value, TWO, ZERO};
+use std::ops::{Index, IndexMut};
+
+pub fn trim<X: Index<usize, Output = Value> + IndexMut<usize, Output = Value>>(
+ size: usize,
+ a: &mut X,
+) {
+ let half = size / 2;
+ let quarter = size / 4;
+ for i in 0..(size / 2 / 4) {
+ let hi = half + i * 4;
+ let qi = quarter + i * 2;
+ a[qi] = (a[qi + 0] + a[qi + 1]) / TWO;
+ a[qi + 1] = (a[hi + 0] + a[hi + 1] + a[hi + 2] + a[hi + 3]) / (TWO * TWO);
+ }
+ for i in half..size {
+ a[i] = ZERO;
+ }
+}
+
+pub fn untrim<X: Index<usize, Output = Value> + IndexMut<usize, Output = Value>>(
+ size: usize,
+ a: &mut X,
+) {
+ let half = size / 2;
+ let quarter = size / 4;
+ for i in 0..(size / 2 / 4) {
+ let hi = half + i * 4;
+ let qi = quarter + i * 2;
+ a[hi + 0] = a[qi + 1];
+ a[hi + 1] = a[qi + 1];
+ a[hi + 2] = a[qi + 1];
+ a[hi + 3] = a[qi + 1];
+ a[qi + 1] = a[qi];
+ }
+}
diff --git a/dhwt-codec/src/view.rs b/dhwt-codec/src/view.rs
new file mode 100644
index 0000000..0f2ecf7
--- /dev/null
+++ b/dhwt-codec/src/view.rs
@@ -0,0 +1,42 @@
+use std::ops::{Index, IndexMut};
+
+use crate::io::{VideoBuf, Value};
+
+#[derive(Copy, Clone, Debug)]
+pub enum IndexMode {
+ XY(usize, usize),
+ XZ(usize, usize),
+ YZ(usize, usize),
+}
+
+pub struct BufferView<'a> {
+ mode: IndexMode,
+ buf: &'a mut VideoBuf,
+}
+
+impl<'a> BufferView<'a> {
+ pub fn new(buf: &'a mut VideoBuf, mode: IndexMode) -> Self {
+ BufferView { mode, buf }
+ }
+}
+
+impl Index<usize> for BufferView<'_> {
+ type Output = Value;
+
+ fn index(&self, a: usize) -> &Self::Output {
+ match self.mode {
+ IndexMode::XY(x, y) => &self.buf[x][y][a],
+ IndexMode::XZ(x, z) => &self.buf[x][a][z],
+ IndexMode::YZ(y, z) => &self.buf[a][y][z],
+ }
+ }
+}
+impl IndexMut<usize> for BufferView<'_> {
+ fn index_mut(&mut self, a: usize) -> &mut Self::Output {
+ match self.mode {
+ IndexMode::XY(x, y) => &mut self.buf[x][y][a],
+ IndexMode::XZ(x, z) => &mut self.buf[x][a][z],
+ IndexMode::YZ(y, z) => &mut self.buf[a][y][z],
+ }
+ }
+}
diff --git a/vgcodec/.gitignore b/vgcodec/.gitignore
new file mode 100644
index 0000000..775fc88
--- /dev/null
+++ b/vgcodec/.gitignore
@@ -0,0 +1,3 @@
+/target
+/a
+
diff --git a/vgcodec/Cargo.lock b/vgcodec/Cargo.lock
new file mode 100644
index 0000000..06a117c
--- /dev/null
+++ b/vgcodec/Cargo.lock
@@ -0,0 +1,1310 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "ahash"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "arrayvec"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
+
+[[package]]
+name = "ash"
+version = "0.37.0+1.3.209"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "006ca68e0f2b03f22d6fa9f2860f85aed430d257fec20f8879b2145e7c7ae1a6"
+dependencies = [
+ "libloading",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bit-set"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+
+[[package]]
+name = "bit_field"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "block"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+
+[[package]]
+name = "bumpalo"
+version = "3.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+
+[[package]]
+name = "bytemuck"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f"
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
+name = "cc"
+version = "1.0.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
+[[package]]
+name = "codespan-reporting"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
+dependencies = [
+ "termcolor",
+ "unicode-width",
+]
+
+[[package]]
+name = "color_quant"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
+
+[[package]]
+name = "core-graphics-types"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
+dependencies = [
+ "cfg-if",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bf8df95e795db1a4aca2957ad884a2df35413b24bbeb3114422f3cc21498e8"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "crossbeam-utils",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "422f23e724af1240ec469ea1e834d87a4b59ce2efe2c6a96256b0c47e2fd86aa"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "cty"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
+
+[[package]]
+name = "d3d12"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "827914e1f53b1e0e025ecd3d967a7836b7bcb54520f90e21ef8df7b4d88a2759"
+dependencies = [
+ "bitflags",
+ "libloading",
+ "winapi",
+]
+
+[[package]]
+name = "either"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+
+[[package]]
+name = "env_logger"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
+dependencies = [
+ "atty",
+ "humantime",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "exr"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eb5f255b5980bb0c8cf676b675d1a99be40f316881444f44e0462eaf5df5ded"
+dependencies = [
+ "bit_field",
+ "flume",
+ "half",
+ "lebe",
+ "miniz_oxide 0.6.2",
+ "smallvec",
+ "threadpool",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide 0.5.4",
+]
+
+[[package]]
+name = "flume"
+version = "0.10.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "nanorand",
+ "pin-project",
+ "spin",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "futures-core"
+version = "0.3.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
+
+[[package]]
+name = "futures-intrusive"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
+dependencies = [
+ "futures-core",
+ "lock_api",
+ "parking_lot",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
+
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "gif"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06"
+dependencies = [
+ "color_quant",
+ "weezl",
+]
+
+[[package]]
+name = "glow"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919"
+dependencies = [
+ "js-sys",
+ "slotmap",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gpu-alloc"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d"
+dependencies = [
+ "bitflags",
+ "gpu-alloc-types",
+]
+
+[[package]]
+name = "gpu-alloc-types"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "gpu-descriptor"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a"
+dependencies = [
+ "bitflags",
+ "gpu-descriptor-types",
+ "hashbrown",
+]
+
+[[package]]
+name = "gpu-descriptor-types"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "half"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554"
+dependencies = [
+ "crunchy",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hexf-parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "image"
+version = "0.24.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945"
+dependencies = [
+ "bytemuck",
+ "byteorder",
+ "color_quant",
+ "exr",
+ "gif",
+ "jpeg-decoder",
+ "num-rational",
+ "num-traits",
+ "png",
+ "scoped_threadpool",
+ "tiff",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "jpeg-decoder"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
+dependencies = [
+ "rayon",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "khronos-egl"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3"
+dependencies = [
+ "libc",
+ "libloading",
+ "pkg-config",
+]
+
+[[package]]
+name = "lebe"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
+
+[[package]]
+name = "libc"
+version = "0.2.137"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "malloc_buf"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "memoffset"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "metal"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060"
+dependencies = [
+ "bitflags",
+ "block",
+ "core-graphics-types",
+ "foreign-types",
+ "log",
+ "objc",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "naga"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "262d2840e72dbe250e8cf2f522d080988dfca624c4112c096238a4845f591707"
+dependencies = [
+ "bit-set",
+ "bitflags",
+ "codespan-reporting",
+ "hexf-parse",
+ "indexmap",
+ "log",
+ "num-traits",
+ "rustc-hash",
+ "spirv",
+ "termcolor",
+ "thiserror",
+ "unicode-xid",
+]
+
+[[package]]
+name = "nanorand"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "objc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+dependencies = [
+ "malloc_buf",
+ "objc_exception",
+]
+
+[[package]]
+name = "objc_exception"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-sys",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+
+[[package]]
+name = "png"
+version = "0.17.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638"
+dependencies = [
+ "bitflags",
+ "crc32fast",
+ "flate2",
+ "miniz_oxide 0.6.2",
+]
+
+[[package]]
+name = "pollster"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "profiling"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74605f360ce573babfe43964cbe520294dcb081afbf8c108fc6e23036b4da2df"
+
+[[package]]
+name = "quote"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "range-alloc"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6"
+
+[[package]]
+name = "raw-window-handle"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a"
+dependencies = [
+ "cty",
+]
+
+[[package]]
+name = "rayon"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
+dependencies = [
+ "crossbeam-deque",
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-utils",
+ "num_cpus",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
+
+[[package]]
+name = "renderdoc-sys"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "scoped_threadpool"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "slotmap"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
+name = "spin"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "spirv"
+version = "0.2.0+1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830"
+dependencies = [
+ "bitflags",
+ "num-traits",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "syn"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "threadpool"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
+dependencies = [
+ "num_cpus",
+]
+
+[[package]]
+name = "tiff"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f17def29300a156c19ae30814710d9c63cd50288a49c6fd3a10ccfbe4cf886fd"
+dependencies = [
+ "flate2",
+ "jpeg-decoder",
+ "weezl",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "vgcodec"
+version = "0.1.0"
+dependencies = [
+ "bytemuck",
+ "env_logger",
+ "futures-intrusive",
+ "image",
+ "log",
+ "pollster",
+ "wgpu",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+
+[[package]]
+name = "web-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "weezl"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
+
+[[package]]
+name = "wgpu"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2272b17bffc8a0c7d53897435da7c1db587c87d3a14e8dae9cdb8d1d210fc0f"
+dependencies = [
+ "arrayvec",
+ "js-sys",
+ "log",
+ "naga",
+ "parking_lot",
+ "raw-window-handle",
+ "smallvec",
+ "static_assertions",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "wgpu-core",
+ "wgpu-hal",
+ "wgpu-types",
+]
+
+[[package]]
+name = "wgpu-core"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73d14cad393054caf992ee02b7da6a372245d39a484f7461c1f44f6f6359bd28"
+dependencies = [
+ "arrayvec",
+ "bit-vec",
+ "bitflags",
+ "cfg_aliases",
+ "codespan-reporting",
+ "fxhash",
+ "log",
+ "naga",
+ "parking_lot",
+ "profiling",
+ "raw-window-handle",
+ "smallvec",
+ "thiserror",
+ "web-sys",
+ "wgpu-hal",
+ "wgpu-types",
+]
+
+[[package]]
+name = "wgpu-hal"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cc320a61acb26be4f549c9b1b53405c10a223fbfea363ec39474c32c348d12f"
+dependencies = [
+ "android_system_properties",
+ "arrayvec",
+ "ash",
+ "bit-set",
+ "bitflags",
+ "block",
+ "core-graphics-types",
+ "d3d12",
+ "foreign-types",
+ "fxhash",
+ "glow",
+ "gpu-alloc",
+ "gpu-descriptor",
+ "js-sys",
+ "khronos-egl",
+ "libloading",
+ "log",
+ "metal",
+ "naga",
+ "objc",
+ "parking_lot",
+ "profiling",
+ "range-alloc",
+ "raw-window-handle",
+ "renderdoc-sys",
+ "smallvec",
+ "thiserror",
+ "wasm-bindgen",
+ "web-sys",
+ "wgpu-types",
+ "winapi",
+]
+
+[[package]]
+name = "wgpu-types"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb6b28ef22cac17b9109b25b3bf8c9a103eeb293d7c5f78653979b09140375f6"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
diff --git a/vgcodec/Cargo.toml b/vgcodec/Cargo.toml
new file mode 100644
index 0000000..5b15036
--- /dev/null
+++ b/vgcodec/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "vgcodec"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+wgpu = "0.14.0"
+log = "0.4.17"
+env_logger = "0.9.3"
+pollster = "0.2.5"
+bytemuck = "1.12.3"
+futures-intrusive = "0.5.0"
+image = "0.24.5"
diff --git a/vgcodec/src/app.rs b/vgcodec/src/app.rs
new file mode 100644
index 0000000..0c063a5
--- /dev/null
+++ b/vgcodec/src/app.rs
@@ -0,0 +1,37 @@
+use std::sync::Arc;
+
+use wgpu::{Adapter, Device, Instance, Queue};
+
+pub struct App {
+ pub instance: Instance,
+ pub device: Device,
+ pub adapter: Adapter,
+ pub queue: Queue,
+}
+
+impl App {
+ pub async fn new() -> Arc<Self> {
+ let instance = wgpu::Instance::new(wgpu::Backends::all());
+ let adapter = instance
+ .request_adapter(&wgpu::RequestAdapterOptions::default())
+ .await
+ .unwrap();
+ let (device, queue) = adapter
+ .request_device(
+ &wgpu::DeviceDescriptor {
+ label: None,
+ features: wgpu::Features::empty(),
+ limits: wgpu::Limits::downlevel_defaults(),
+ },
+ None,
+ )
+ .await
+ .unwrap();
+ Arc::new(Self {
+ adapter,
+ device,
+ instance,
+ queue,
+ })
+ }
+}
diff --git a/vgcodec/src/diff.rs b/vgcodec/src/diff.rs
new file mode 100644
index 0000000..44efabe
--- /dev/null
+++ b/vgcodec/src/diff.rs
@@ -0,0 +1,120 @@
+use std::{borrow::Cow, sync::Arc};
+use wgpu::{util::DeviceExt, BindGroup, Buffer, ComputePipeline, Extent3d, Texture};
+
+use crate::app::App;
+
+pub struct Differ {
+ app: Arc<App>,
+ size: Extent3d,
+
+ pipeline: ComputePipeline,
+ bind_group: BindGroup,
+
+ counter_buffer_size: u64,
+ counter_buffer: Buffer,
+ counter_staging_buffer: Buffer,
+}
+
+impl Differ {
+ pub fn new(app: &Arc<App>, extent: Extent3d, tex_a: &Texture, tex_b: &Texture) -> Self {
+ let App { device, .. } = app.as_ref();
+ let cs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
+ label: None,
+ source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("diff.wgsl"))),
+ });
+
+ let counter_buffer_size = std::mem::size_of::<u32>() as wgpu::BufferAddress;
+ let counter_staging_buffer = device.create_buffer(&wgpu::BufferDescriptor {
+ label: None,
+ size: counter_buffer_size,
+ usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
+ mapped_at_creation: false,
+ });
+ let counter_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+ label: None,
+ contents: bytemuck::cast_slice(&[0u32]),
+ usage: wgpu::BufferUsages::STORAGE
+ | wgpu::BufferUsages::COPY_DST
+ | wgpu::BufferUsages::COPY_SRC,
+ });
+
+ let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
+ label: None,
+ layout: None,
+ module: &cs_module,
+ entry_point: "main",
+ });
+
+ let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+ label: None,
+ layout: &pipeline.get_bind_group_layout(0),
+ entries: &[
+ wgpu::BindGroupEntry {
+ binding: 0,
+ resource: wgpu::BindingResource::TextureView(
+ &tex_a.create_view(&wgpu::TextureViewDescriptor::default()),
+ ),
+ },
+ wgpu::BindGroupEntry {
+ binding: 1,
+ resource: wgpu::BindingResource::TextureView(
+ &tex_b.create_view(&wgpu::TextureViewDescriptor::default()),
+ ),
+ },
+ wgpu::BindGroupEntry {
+ binding: 2,
+ resource: counter_buffer.as_entire_binding(),
+ },
+ ],
+ });
+ Self {
+ app: app.clone(),
+ size: extent,
+ pipeline,
+ counter_buffer_size,
+ counter_buffer,
+ bind_group,
+ counter_staging_buffer,
+ }
+ }
+
+ pub async fn run(&mut self) -> u32 {
+ let App { device, queue, .. } = self.app.as_ref();
+
+ let mut encoder =
+ device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
+ {
+ let mut cpass =
+ encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None });
+ cpass.set_pipeline(&self.pipeline);
+ cpass.set_bind_group(0, &self.bind_group, &[]);
+ cpass.dispatch_workgroups(self.size.width, self.size.height, 1);
+ }
+
+ encoder.copy_buffer_to_buffer(
+ &self.counter_buffer,
+ 0,
+ &self.counter_staging_buffer,
+ 0,
+ self.counter_buffer_size,
+ );
+
+ queue.submit(Some(encoder.finish()));
+
+ let buffer_slice = self.counter_staging_buffer.slice(..);
+ let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel();
+ buffer_slice.map_async(wgpu::MapMode::Read, move |v| {
+ sender.send(v.unwrap()).unwrap()
+ });
+ device.poll(wgpu::Maintain::Wait);
+ receiver.receive().await;
+
+ let data = buffer_slice.get_mapped_range();
+ let result: u32 = bytemuck::cast_slice(&data).to_vec()[0];
+
+ drop(data);
+ self.counter_staging_buffer.unmap();
+
+ result
+ }
+}
diff --git a/vgcodec/src/diff.wgsl b/vgcodec/src/diff.wgsl
new file mode 100644
index 0000000..bb5a3e1
--- /dev/null
+++ b/vgcodec/src/diff.wgsl
@@ -0,0 +1,17 @@
+@group(0) @binding(0)
+var tex_a: texture_2d<f32>;
+@group(0) @binding(1)
+var tex_b: texture_2d<f32>;
+
+@group(0) @binding(2)
+var<storage, read_write> exp: atomic<u32>;
+
+@compute @workgroup_size(1)
+fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
+ var col_a = textureLoad(tex_a, vec2(i32(global_id.x), i32(global_id.y)), 0);
+ var col_b = textureLoad(tex_b, vec2(i32(global_id.x), i32(global_id.y)), 0);
+ var diff = col_a - col_b;
+ var diffsum = diff.r + diff.g + diff.b;
+ atomicAdd(&exp, u32(diffsum));
+}
+
diff --git a/vgcodec/src/export.rs b/vgcodec/src/export.rs
new file mode 100644
index 0000000..7b02085
--- /dev/null
+++ b/vgcodec/src/export.rs
@@ -0,0 +1,80 @@
+use crate::app::App;
+use image::RgbaImage;
+use std::{num::NonZeroU32, sync::Arc};
+use wgpu::{
+ Buffer, Extent3d, ImageCopyBuffer, ImageCopyTexture, ImageDataLayout, Origin3d, Texture,
+};
+
+pub struct Exporter {
+ app: Arc<App>,
+ size: Extent3d,
+
+ padded_bytes_per_row: u32,
+ export_buffer: Buffer,
+}
+
+impl Exporter {
+ pub fn new(app: &Arc<App>, size: Extent3d) -> Self {
+ let App { device, .. } = app.as_ref();
+
+ let bytes_per_pixel = std::mem::size_of::<u32>() as u32;
+ let unpadded_bytes_per_row = size.width * bytes_per_pixel;
+ let align = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT;
+ let padded_bytes_per_row_padding = (align - unpadded_bytes_per_row % align) % align;
+ let padded_bytes_per_row = unpadded_bytes_per_row + padded_bytes_per_row_padding;
+
+ let export_buffer_size = (padded_bytes_per_row * size.height) as u64;
+ let export_buffer = device.create_buffer(&wgpu::BufferDescriptor {
+ label: None,
+ size: export_buffer_size,
+ usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
+ mapped_at_creation: false,
+ });
+
+ Self {
+ padded_bytes_per_row,
+ app: app.clone(),
+ size,
+ export_buffer,
+ }
+ }
+ pub async fn run(&self, texture: &Texture, save_path: &str) {
+ let App { device, queue, .. } = self.app.as_ref();
+
+ let mut encoder =
+ device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
+
+ encoder.copy_texture_to_buffer(
+ ImageCopyTexture {
+ texture,
+ aspect: wgpu::TextureAspect::All,
+ mip_level: 0,
+ origin: Origin3d::ZERO,
+ },
+ ImageCopyBuffer {
+ buffer: &self.export_buffer,
+ layout: ImageDataLayout {
+ offset: 0,
+ bytes_per_row: Some(NonZeroU32::new(self.padded_bytes_per_row).unwrap()),
+ rows_per_image: None,
+ },
+ },
+ self.size,
+ );
+
+ queue.submit(Some(encoder.finish()));
+
+ let buffer_slice = self.export_buffer.slice(..);
+ let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel();
+ buffer_slice.map_async(wgpu::MapMode::Read, move |v| {
+ sender.send(v.unwrap()).unwrap()
+ });
+ device.poll(wgpu::Maintain::Wait);
+ receiver.receive().await;
+
+ let data = buffer_slice.get_mapped_range();
+ let result: Vec<u8> = bytemuck::cast_slice(&data).to_vec();
+ let image = RgbaImage::from_raw(self.size.width, self.size.height, result).unwrap();
+ image.save(save_path).unwrap();
+ }
+}
diff --git a/vgcodec/src/main.rs b/vgcodec/src/main.rs
new file mode 100644
index 0000000..9450894
--- /dev/null
+++ b/vgcodec/src/main.rs
@@ -0,0 +1,76 @@
+pub mod app;
+pub mod diff;
+pub mod export;
+pub mod paint;
+
+use app::App;
+use diff::Differ;
+use image::EncodableLayout;
+use wgpu::{Extent3d, Queue, Texture, TextureUsages};
+
+use crate::export::Exporter;
+
+fn main() {
+ env_logger::init_from_env("LOG");
+ pollster::block_on(run());
+}
+
+async fn run() {
+ let app = app::App::new().await;
+
+ let App { device, queue, .. } = app.as_ref();
+
+ let img_target = image::open("a/a.png").unwrap().into_rgba8();
+ let img_initial = image::open("a/initial.png").unwrap().into_rgba8();
+
+ let size = wgpu::Extent3d {
+ width: img_initial.width(),
+ height: img_initial.height(),
+ depth_or_array_layers: 1,
+ };
+
+ let create_texture = || {
+ device.create_texture(&wgpu::TextureDescriptor {
+ size,
+ mip_level_count: 1,
+ sample_count: 1,
+ dimension: wgpu::TextureDimension::D2,
+ format: wgpu::TextureFormat::Rgba8Unorm,
+ usage: TextureUsages::COPY_DST
+ | TextureUsages::TEXTURE_BINDING
+ | TextureUsages::COPY_SRC,
+ label: None,
+ })
+ };
+
+ let tex_target = create_texture();
+ let tex_approx = create_texture();
+
+ write_texture(queue, &tex_target, img_target.as_bytes(), size);
+ write_texture(queue, &tex_approx, img_initial.as_bytes(), size);
+
+ let mut differ = Differ::new(&app, size, &tex_approx, &tex_target);
+ let exporter = Exporter::new(&app, size);
+
+ println!("{}", differ.run().await);
+
+ exporter.run(&tex_approx, "a/approx.png").await;
+}
+
+pub fn write_texture(queue: &Queue, target: &Texture, data: &[u8], size: Extent3d) {
+ queue.write_texture(
+ wgpu::ImageCopyTexture {
+ texture: &target,
+ mip_level: 0,
+ origin: wgpu::Origin3d::ZERO,
+ aspect: wgpu::TextureAspect::All,
+ },
+ &data,
+ wgpu::ImageDataLayout {
+ offset: 0,
+ bytes_per_row: Some(std::num::NonZeroU32::try_from((size.width * 4) as u32).unwrap()),
+ rows_per_image: None,
+ },
+ size,
+ );
+}
diff --git a/vgcodec/src/paint.rs b/vgcodec/src/paint.rs
new file mode 100644
index 0000000..3da0647
--- /dev/null
+++ b/vgcodec/src/paint.rs
@@ -0,0 +1,120 @@
+use std::{borrow::Cow, sync::Arc};
+use wgpu::{util::DeviceExt, BindGroup, Buffer, ComputePipeline, Extent3d, Texture};
+
+use crate::app::App;
+
+pub struct Painter {
+ app: Arc<App>,
+ size: Extent3d,
+
+ pipeline: ComputePipeline,
+ bind_group: BindGroup,
+
+ uniform_buffer_size: u64,
+ uniform_buffer: Buffer,
+ uniform_staging_buffer: Buffer,
+}
+
+impl Painter {
+ pub fn new(app: &Arc<App>, extent: Extent3d, tex_a: &Texture, tex_b: &Texture) -> Self {
+ let App { device, .. } = app.as_ref();
+ let cs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
+ label: None,
+ source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("paint.wgsl"))),
+ });
+
+ let uniform_buffer_size = std::mem::size_of::<u32>() as wgpu::BufferAddress;
+ let uniform_staging_buffer = device.create_buffer(&wgpu::BufferDescriptor {
+ label: None,
+ size: uniform_buffer_size,
+ usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST,
+ mapped_at_creation: false,
+ });
+ let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+ label: None,
+ contents: bytemuck::cast_slice(&[0u32]),
+ usage: wgpu::BufferUsages::STORAGE
+ | wgpu::BufferUsages::COPY_DST
+ | wgpu::BufferUsages::COPY_SRC,
+ });
+
+ let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
+ label: None,
+ layout: None,
+ module: &cs_module,
+ entry_point: "main",
+ });
+
+ let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+ label: None,
+ layout: &pipeline.get_bind_group_layout(0),
+ entries: &[
+ wgpu::BindGroupEntry {
+ binding: 0,
+ resource: wgpu::BindingResource::TextureView(
+ &tex_a.create_view(&wgpu::TextureViewDescriptor::default()),
+ ),
+ },
+ wgpu::BindGroupEntry {
+ binding: 1,
+ resource: wgpu::BindingResource::TextureView(
+ &tex_b.create_view(&wgpu::TextureViewDescriptor::default()),
+ ),
+ },
+ wgpu::BindGroupEntry {
+ binding: 2,
+ resource: uniform_buffer.as_entire_binding(),
+ },
+ ],
+ });
+ Self {
+ app: app.clone(),
+ size: extent,
+ pipeline,
+ uniform_buffer_size,
+ uniform_buffer,
+ bind_group,
+ uniform_staging_buffer,
+ }
+ }
+
+ pub async fn run(&mut self) -> u32 {
+ let App { device, queue, .. } = self.app.as_ref();
+
+ let mut encoder =
+ device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
+ {
+ let mut cpass =
+ encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None });
+ cpass.set_pipeline(&self.pipeline);
+ cpass.set_bind_group(0, &self.bind_group, &[]);
+ cpass.dispatch_workgroups(self.size.width, self.size.height, 1);
+ }
+
+ encoder.copy_buffer_to_buffer(
+ &self.uniform_buffer,
+ 0,
+ &self.uniform_staging_buffer,
+ 0,
+ self.uniform_buffer_size,
+ );
+
+ queue.submit(Some(encoder.finish()));
+
+ let buffer_slice = self.uniform_staging_buffer.slice(..);
+ let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel();
+ buffer_slice.map_async(wgpu::MapMode::Read, move |v| {
+ sender.send(v.unwrap()).unwrap()
+ });
+ device.poll(wgpu::Maintain::Wait);
+ receiver.receive().await;
+
+ let data = buffer_slice.get_mapped_range();
+ let result: u32 = bytemuck::cast_slice(&data).to_vec()[0];
+
+ drop(data);
+ self.uniform_staging_buffer.unmap();
+
+ result
+ }
+}
diff --git a/vgcodec/src/paint.wgsl b/vgcodec/src/paint.wgsl
new file mode 100644
index 0000000..02acd8e
--- /dev/null
+++ b/vgcodec/src/paint.wgsl
@@ -0,0 +1,19 @@
+struct Uniforms {
+ x: f32,
+ y: f32,
+ radius: f32,
+ r: f32,
+ g: f32,
+ b: f32
+};
+
+@group(0) @binding(0) var<uniform> uniforms: Uniforms;
+@group(0) @binding(1) var tex: texture_storage_2d<rgba8unorm, write>;
+
+@compute @workgroup_size(1)
+fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
+ let coords = vec2<i32>(global_id.xy);
+ if distance(vec2<f32>(coords), vec2(uniforms.x, uniforms.y)) < uniforms.radius {
+ textureStore(tex, coords.xy, vec4<f32>(vec3<f32>(uniforms.r, uniforms.g, uniforms.b), 1.0));
+ }
+}