aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vgcodec/Cargo.lock80
-rw-r--r--vgcodec/Cargo.toml1
-rw-r--r--vgcodec/src/approximate.rs78
-rw-r--r--vgcodec/src/helper.rs14
-rw-r--r--vgcodec/src/main.rs20
-rw-r--r--vgcodec/src/paint.rs3
-rw-r--r--vgcodec/src/paint.wgsl7
7 files changed, 162 insertions, 41 deletions
diff --git a/vgcodec/Cargo.lock b/vgcodec/Cargo.lock
index 390443b..41f0fcf 100644
--- a/vgcodec/Cargo.lock
+++ b/vgcodec/Cargo.lock
@@ -153,6 +153,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[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 = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -468,6 +505,12 @@ dependencies = [
]
[[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"
@@ -738,6 +781,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
+name = "os_str_bytes"
+version = "6.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
+
+[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -811,6 +860,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[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"
@@ -993,6 +1066,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[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"
@@ -1081,6 +1160,7 @@ name = "vgcodec"
version = "0.1.0"
dependencies = [
"bytemuck",
+ "clap",
"env_logger",
"futures-intrusive",
"image",
diff --git a/vgcodec/Cargo.toml b/vgcodec/Cargo.toml
index dd76753..b9a8415 100644
--- a/vgcodec/Cargo.toml
+++ b/vgcodec/Cargo.toml
@@ -12,3 +12,4 @@ bytemuck = { version = "1.12.3", features = ["derive"] }
futures-intrusive = "0.5.0"
image = "0.24.5"
rand = "0.8.5"
+clap = { version = "4.0.26", features = ["derive"] }
diff --git a/vgcodec/src/approximate.rs b/vgcodec/src/approximate.rs
index fc2b4ba..c4dc629 100644
--- a/vgcodec/src/approximate.rs
+++ b/vgcodec/src/approximate.rs
@@ -1,17 +1,13 @@
-use std::sync::Arc;
-
-use image::EncodableLayout;
-use log::info;
-use rand::Rng;
-use wgpu::{Extent3d, Texture, TextureUsages};
-
use crate::{
app::App,
diff::Differ,
export::Exporter,
- helper::write_texture,
paint::{PaintUniforms, Painter},
};
+use log::{debug, info};
+use rand::Rng;
+use std::sync::Arc;
+use wgpu::{Extent3d, Texture, TextureUsages};
#[allow(unused)]
pub struct Approximator {
@@ -28,7 +24,7 @@ pub struct Approximator {
impl Approximator {
pub fn new(app: &Arc<App>, tex_target: Texture, size: Extent3d) -> Self {
- let App { device, queue, .. } = app.as_ref();
+ let App { device, .. } = app.as_ref();
let tex_approx = device.create_texture(&wgpu::TextureDescriptor {
size,
mip_level_count: 1,
@@ -51,8 +47,8 @@ impl Approximator {
label: None,
});
- let img_initial = image::open("a/initial.png").unwrap().into_rgba8();
- write_texture(queue, &tex_approx, img_initial.as_bytes(), size);
+ // let initial_init = (0..)
+ // write_texture(queue, &tex_approx, initial_init, size);
let differ = Differ::new(&app, size, &tex_approx, &tex_target);
let painter = Painter::new(&app, size, &tex_approx);
@@ -79,44 +75,62 @@ impl Approximator {
.copy_texture(&self.tex_savestate, &self.tex_approx, self.size);
}
- pub async fn run(&mut self) {
- for _ in 0..10 {
+ pub async fn run(&mut self, iters: usize) {
+ let rscale = self.size.width as f32 * 0.1;
+ for i in 0..iters {
let mut p = PaintUniforms {
- x: rand::thread_rng().gen_range(0.0..256.0),
- y: rand::thread_rng().gen_range(0.0..256.0),
+ x: rand::thread_rng().gen_range(0.0..self.size.width as f32),
+ y: rand::thread_rng().gen_range(0.0..self.size.height as f32),
+ rx: rscale,
+ ry: rscale,
r: rand::thread_rng().gen_range(0.0..1.0),
g: rand::thread_rng().gen_range(0.0..1.0),
b: rand::thread_rng().gen_range(0.0..1.0),
- radius: rand::thread_rng().gen_range(5.0..10.0),
};
// Find initial diff
self.save();
self.painter.run(p);
- let mut cd = pollster::block_on(self.differ.run());
- info!("initial diff={cd}");
+ let initial_diff = pollster::block_on(self.differ.run());
+ debug!("initial diff={initial_diff}");
self.restore();
+ let mut cd = initial_diff;
self.save();
loop {
let mut q = 0;
- q += self.optimize_param(&mut cd, &mut p, "more red", |p| p.r += 0.1);
- q += self.optimize_param(&mut cd, &mut p, "less red", |p| p.r -= 0.1);
- q += self.optimize_param(&mut cd, &mut p, "more green", |p| p.g += 0.1);
- q += self.optimize_param(&mut cd, &mut p, "less green", |p| p.g -= 0.1);
- q += self.optimize_param(&mut cd, &mut p, "more blue", |p| p.b += 0.1);
- q += self.optimize_param(&mut cd, &mut p, "less blue", |p| p.b -= 0.1);
- q += self.optimize_param(&mut cd, &mut p, "increase radius", |p| p.radius *= 1.5);
- q += self.optimize_param(&mut cd, &mut p, "decrease radius", |p| p.radius *= 1.5);
- q += self.optimize_param(&mut cd, &mut p, "move right", |p| p.x += 5.0);
- q += self.optimize_param(&mut cd, &mut p, "move left", |p| p.x -= 5.0);
- q += self.optimize_param(&mut cd, &mut p, "move down", |p| p.y += 5.0);
- q += self.optimize_param(&mut cd, &mut p, "move up", |p| p.y -= 5.0);
+ let mut k = |k: usize| {
+ q += k;
+ q == 0
+ };
+ if k(self.optimize_param(&mut cd, &mut p, "more red", |p| p.r += 0.1)) {
+ k(self.optimize_param(&mut cd, &mut p, "less red", |p| p.r -= 0.1));
+ }
+ if k(self.optimize_param(&mut cd, &mut p, "more green", |p| p.g += 0.1)) {
+ k(self.optimize_param(&mut cd, &mut p, "less green", |p| p.g -= 0.1));
+ }
+ if k(self.optimize_param(&mut cd, &mut p, "more blue", |p| p.b += 0.1)) {
+ k(self.optimize_param(&mut cd, &mut p, "less blue", |p| p.b -= 0.1));
+ }
+ if k(self.optimize_param(&mut cd, &mut p, "increase rx", |p| p.rx *= 1.5)) {
+ k(self.optimize_param(&mut cd, &mut p, "decrease rx", |p| p.rx /= 1.5));
+ }
+ if k(self.optimize_param(&mut cd, &mut p, "increase ry", |p| p.ry *= 1.5)) {
+ k(self.optimize_param(&mut cd, &mut p, "decrease ry", |p| p.ry /= 1.5));
+ }
+ if k(self.optimize_param(&mut cd, &mut p, "move right", |p| p.x += 5.0)) {
+ k(self.optimize_param(&mut cd, &mut p, "move left", |p| p.x -= 5.0));
+ }
+ if k(self.optimize_param(&mut cd, &mut p, "move down", |p| p.y += 5.0)) {
+ k(self.optimize_param(&mut cd, &mut p, "move up", |p| p.y -= 5.0));
+ }
if q == 0 {
break;
}
}
self.painter.run(p);
+
+ info!("{i} (improvement={})", initial_diff - cd);
}
self.exporter.run(&self.tex_approx, "a/approx.png").await;
@@ -139,13 +153,15 @@ impl Approximator {
self.painter.run(p);
let diff = pollster::block_on(self.differ.run());
// pollster::block_on(self.exporter.run(&self.tex_approx, &format!("a/snap.png")));
+ debug!("try {label:?} ({})", diff as i64 - *current_diff as i64);
self.restore();
if diff >= *current_diff {
break i;
}
- info!("applied {label:?} (before={current_diff} after={diff})");
+ debug!("applied {label:?}");
i += 1;
*current_diff = diff;
+ *params = p
}
}
}
diff --git a/vgcodec/src/helper.rs b/vgcodec/src/helper.rs
index 3aca81d..1d029b8 100644
--- a/vgcodec/src/helper.rs
+++ b/vgcodec/src/helper.rs
@@ -1,7 +1,15 @@
-use wgpu::{Queue, Texture, Extent3d};
-
+use log::info;
+use wgpu::{Extent3d, Queue, Texture};
pub fn write_texture(queue: &Queue, target: &Texture, data: &[u8], size: Extent3d) {
+ info!("uploading texture {size:?} ({} bytes)", data.len());
+
+ 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;
+
queue.write_texture(
wgpu::ImageCopyTexture {
texture: &target,
@@ -12,7 +20,7 @@ pub fn write_texture(queue: &Queue, target: &Texture, data: &[u8], size: Extent3
&data,
wgpu::ImageDataLayout {
offset: 0,
- bytes_per_row: Some(std::num::NonZeroU32::try_from((size.width * 4) as u32).unwrap()),
+ bytes_per_row: Some(std::num::NonZeroU32::try_from(padded_bytes_per_row).unwrap()),
rows_per_image: None,
},
size,
diff --git a/vgcodec/src/main.rs b/vgcodec/src/main.rs
index 7fb0750..2be0793 100644
--- a/vgcodec/src/main.rs
+++ b/vgcodec/src/main.rs
@@ -7,8 +7,9 @@ pub mod paint;
use app::App;
use approximate::Approximator;
+use clap::Parser;
use helper::write_texture;
-use image::EncodableLayout;
+use log::info;
use wgpu::TextureUsages;
fn main() {
@@ -16,12 +17,21 @@ fn main() {
pollster::block_on(run());
}
+#[derive(Parser)]
+#[clap(about)]
+struct Args {
+ #[clap(short = 'I', long)]
+ iterations: usize,
+ infile: String,
+}
+
async fn run() {
+ let args = Args::parse();
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_target = image::open(&args.infile).unwrap().into_rgba8();
let size = wgpu::Extent3d {
width: img_target.width(),
@@ -39,8 +49,10 @@ async fn run() {
label: None,
});
- write_texture(queue, &tex_target, img_target.as_bytes(), size);
+ let img_raw = img_target.into_raw();
+ info!("{}", img_raw.len());
+ write_texture(queue, &tex_target, &img_raw, size);
let mut a = Approximator::new(&app, tex_target, size);
- a.run().await;
+ a.run(args.iterations).await;
}
diff --git a/vgcodec/src/paint.rs b/vgcodec/src/paint.rs
index f25b749..33ab572 100644
--- a/vgcodec/src/paint.rs
+++ b/vgcodec/src/paint.rs
@@ -19,7 +19,8 @@ pub struct Painter {
pub struct PaintUniforms {
pub x: f32,
pub y: f32,
- pub radius: f32,
+ pub rx: f32,
+ pub ry: f32,
pub r: f32,
pub g: f32,
pub b: f32,
diff --git a/vgcodec/src/paint.wgsl b/vgcodec/src/paint.wgsl
index f23e903..7006310 100644
--- a/vgcodec/src/paint.wgsl
+++ b/vgcodec/src/paint.wgsl
@@ -1,7 +1,8 @@
struct Uniforms {
x: f32,
y: f32,
- radius: f32,
+ rx: f32,
+ ry: f32,
r: f32,
g: f32,
b: f32
@@ -13,7 +14,9 @@ struct Uniforms {
@compute @workgroup_size(1)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let coords = global_id.xy;
- if distance(vec2<f32>(coords), vec2(uniforms.x, uniforms.y)) < uniforms.radius {
+ let kc = vec2<f32>(coords) - vec2(uniforms.x, uniforms.y);
+ let d = length(kc / vec2(uniforms.rx, uniforms.ry));
+ if d < 1.0 {
textureStore(tex, vec2<i32>(coords), vec4<f32>(vec3<f32>(uniforms.r, uniforms.g, uniforms.b), 1.0));
}
}