aboutsummaryrefslogtreecommitdiff
path: root/evc
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2022-12-08 09:13:17 +0100
committermetamuffin <metamuffin@disroot.org>2022-12-08 09:13:17 +0100
commit6001cdeff335e12583a398acbb5a8a42c01bc077 (patch)
tree4c1c515cbf33e727f5db317880aadd425a1e0b96 /evc
parent8b7792d6aa27578221fee7cc8be1ceb202602a5a (diff)
downloadvideo-codec-experiments-6001cdeff335e12583a398acbb5a8a42c01bc077.tar
video-codec-experiments-6001cdeff335e12583a398acbb5a8a42c01bc077.tar.bz2
video-codec-experiments-6001cdeff335e12583a398acbb5a8a42c01bc077.tar.zst
fast mode
Diffstat (limited to 'evc')
-rw-r--r--evc/.gitignore3
-rw-r--r--evc/Cargo.lock4
-rw-r--r--evc/spec.md8
-rw-r--r--evc/src/bin/decode.rs11
-rw-r--r--evc/src/bin/encode.rs21
-rw-r--r--evc/src/block.rs57
-rw-r--r--evc/src/codec/decode.rs32
-rw-r--r--evc/src/codec/encode.rs177
-rw-r--r--evc/src/format/ser.rs22
-rw-r--r--evc/src/helpers/pixel.rs22
-rw-r--r--evc/src/helpers/vector.rs3
-rw-r--r--evc/src/refsampler.rs2
12 files changed, 244 insertions, 118 deletions
diff --git a/evc/.gitignore b/evc/.gitignore
index 870bad6..b88f3af 100644
--- a/evc/.gitignore
+++ b/evc/.gitignore
@@ -1,3 +1,6 @@
/target
/samples
/reports
+/flamegraph.svg
+/perf.data*
+
diff --git a/evc/Cargo.lock b/evc/Cargo.lock
index e804305..22ef8be 100644
--- a/evc/Cargo.lock
+++ b/evc/Cargo.lock
@@ -259,9 +259,9 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rustix"
-version = "0.36.4"
+version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23"
+checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
dependencies = [
"bitflags",
"errno",
diff --git a/evc/spec.md b/evc/spec.md
index 9d4cc62..77f6b7d 100644
--- a/evc/spec.md
+++ b/evc/spec.md
@@ -8,13 +8,13 @@
- frames (repeated [frame count]-times)
- block type
- block
- - **Literal-Block** (pixels saved)
+ - 0 **Literal-Block** (pixels saved)
- pixels: _`[[u8; 3]]`_
- - **Split-Block** (delegated to 2 sub-blocks split on the longest axis)
+ - 1 **Split-Block** (delegated to 2 sub-blocks split on the longest axis)
- sub-blocks: _`[block; 2]` (see above)_
- - **Reference-Block** (reuses previous frame in some way)
+ - 2 **Reference-Block** (reuses previous frame in some way)
- translation: _`i8, i8`_
- - **Advanced-Reference-Block** (reuses previous frame in some way)
+ - 3 **Advanced-Reference-Block** (reuses previous frame in some way)
- translation: _`s8, s8`_ (translation encoded as _floats_)
- transform: _`s8, s8, s8, s8`_ (2x2-matrix of _floats_ applied before
sampling)
diff --git a/evc/src/bin/decode.rs b/evc/src/bin/decode.rs
index 5cbd29e..c2b3b4d 100644
--- a/evc/src/bin/decode.rs
+++ b/evc/src/bin/decode.rs
@@ -3,7 +3,7 @@ use anyhow::Context;
use clap::Parser;
use evc::{
block::Block,
- codec::decode::decode_block,
+ codec::decode::{decode_block, DecodeConfig},
debug::draw_debug,
format::{header::Header, ser::Source},
frame::Frame,
@@ -16,6 +16,9 @@ use std::io::{BufReader, BufWriter};
pub struct DecodeArgs {
#[arg(long)]
debug: bool,
+
+ #[arg(short, long, default_value = "8")]
+ jobs: usize,
}
fn main() -> anyhow::Result<()> {
@@ -29,6 +32,10 @@ fn main() -> anyhow::Result<()> {
info!("{header:?}");
let size = header.resolution;
+ let config = DecodeConfig {
+ max_threads: args.jobs,
+ };
+
let mut prev = Frame::new(size);
for i in 0.. {
info!("decode frame {i}");
@@ -36,7 +43,7 @@ fn main() -> anyhow::Result<()> {
let block = Block::read(&mut input, size).context("reading encoded frame")?;
let mut frame = Frame::new(size);
- decode_block(&block, frame.view_mut(), prev.view());
+ decode_block(&block, frame.view_mut(), prev.view(), &config);
if args.debug {
let mut f2 = frame.clone();
diff --git a/evc/src/bin/encode.rs b/evc/src/bin/encode.rs
index fe03023..d27074e 100644
--- a/evc/src/bin/encode.rs
+++ b/evc/src/bin/encode.rs
@@ -20,7 +20,7 @@ pub struct EncodeArgs {
#[arg(short = 'H', long)]
height: usize,
- #[arg(short, long, default_value = "advanced")]
+ #[arg(short, long, default_value = "default")]
mode: EncodeMode,
#[arg(short, long, default_value = "8")]
@@ -29,10 +29,8 @@ pub struct EncodeArgs {
#[arg(short, long, default_value = "8")]
min_block_size: isize,
- #[arg(short = 't', long, default_value = "100")]
+ #[arg(short = 't', long, default_value = "200")]
ref_thres: f64,
- #[arg(short = 'T', long)]
- no_translation: bool,
}
fn main() -> anyhow::Result<()> {
@@ -45,9 +43,12 @@ fn main() -> anyhow::Result<()> {
let config = EncodeConfig {
mode: args.mode,
ref_thres: args.ref_thres,
+ weight_factor: 50.0,
max_diff_area: 10_000,
min_block_size: args.min_block_size,
max_threads: args.jobs,
+ do_matrix_transform: false,
+ do_value_scale: false,
};
let size = Vec2 {
@@ -72,9 +73,17 @@ fn main() -> anyhow::Result<()> {
let v2 = prev_frame.view();
let root = encode_block(v1, v2, &config);
- root.write(&mut output).context("writing encoded frame")?;
+ root.write(&mut output, size)
+ .context("writing encoded frame")?;
- decode_block(&root, frame.view_mut(), prev_frame.view());
+ decode_block(
+ &root,
+ frame.view_mut(),
+ prev_frame.view(),
+ &evc::codec::decode::DecodeConfig {
+ max_threads: config.max_threads,
+ },
+ );
prev_frame = frame;
}
diff --git a/evc/src/block.rs b/evc/src/block.rs
index 24691e8..04ee3d2 100644
--- a/evc/src/block.rs
+++ b/evc/src/block.rs
@@ -1,10 +1,9 @@
-use anyhow::bail;
-
use crate::{
- format::ser::{Ser, Sink, Small, Source},
+ format::ser::{ConstSizeSerExt, Sink, Small, Source},
helpers::vector::Vec2,
helpers::{matrix::Mat2, pixel::Pixel},
};
+use anyhow::bail;
#[derive(Clone, Debug)]
pub enum Block {
@@ -22,16 +21,21 @@ pub struct AdvancedReference {
}
impl Block {
- pub fn write(&self, sink: &mut impl std::io::Write) -> anyhow::Result<()> {
+ pub const REFZERO: Block = Block::Reference {
+ translation: Vec2::<isize>::ZERO,
+ };
+
+ pub fn write(&self, sink: &mut impl std::io::Write, size: Vec2<isize>) -> anyhow::Result<()> {
match &self {
Block::Literal(pixels) => {
sink.put(0u8)?;
- pixels.write(sink)?;
+ pixels.write_const_size(sink, size.area() as usize)?;
}
Block::Split(box [a, b]) => {
sink.put(1u8)?;
- a.write(sink)?;
- b.write(sink)?;
+ let [asize, bsize] = split_size(size);
+ a.write(sink, asize)?;
+ b.write(sink, bsize)?;
}
Block::Reference { translation } => {
sink.put(2u8)?;
@@ -51,20 +55,9 @@ impl Block {
pub fn read(source: &mut impl std::io::Read, size: Vec2<isize>) -> anyhow::Result<Self> {
Ok(match source.get::<u8>()? {
- 0 => Block::Literal(source.get()?),
+ 0 => Block::Literal(Vec::read_const_size(source, size.area() as usize)?),
1 => Block::Split(Box::new({
- let vert = size.x > size.y;
- let asize = if vert {
- (size.x / 2, size.y).into()
- } else {
- (size.x, size.y / 2).into()
- };
- let bsize = if vert {
- (size.x - size.x / 2, size.y).into()
- } else {
- (size.x, size.y - size.y / 2).into()
- };
-
+ let [asize, bsize] = split_size(size);
let a = Block::read(source, asize)?;
let b = Block::read(source, bsize)?;
[a, b]
@@ -82,10 +75,34 @@ impl Block {
}
}
+pub fn split_size(size: Vec2<isize>) -> [Vec2<isize>; 2] {
+ let vert = size.x > size.y;
+ [
+ if vert {
+ (size.x / 2, size.y).into()
+ } else {
+ (size.x, size.y / 2).into()
+ },
+ if vert {
+ (size.x - size.x / 2, size.y).into()
+ } else {
+ (size.x, size.y - size.y / 2).into()
+ },
+ ]
+}
+
impl Block {
pub fn is_literal(&self) -> bool {
matches!(self, Block::Literal(..))
}
+ pub fn is_ref_without_translation(&self) -> bool {
+ matches!(
+ self,
+ Block::Reference {
+ translation: Vec2::<isize>::ZERO
+ }
+ )
+ }
}
impl Default for AdvancedReference {
diff --git a/evc/src/codec/decode.rs b/evc/src/codec/decode.rs
index b7ab8c7..197028c 100644
--- a/evc/src/codec/decode.rs
+++ b/evc/src/codec/decode.rs
@@ -1,13 +1,33 @@
-use crate::{block::Block, frame::Frame, refsampler::Sampler, view::View};
+use crate::{
+ block::Block, frame::Frame, helpers::threading::both_par, refsampler::Sampler, view::View,
+};
-pub fn decode_block(block: &Block, mut target: View<&mut Frame>, prev: View<&Frame>) {
+pub struct DecodeConfig {
+ pub max_threads: usize,
+}
+
+pub fn decode_block(
+ block: &Block,
+ mut target: View<&mut Frame>,
+ prev: View<&Frame>,
+ config: &DecodeConfig,
+) {
match &block {
Block::Literal(pixels) => target.set_pixels(pixels),
Block::Split(box [a, b]) => {
- let [at, bt] = target.split_mut_unsafe();
- let [ap, bp] = prev.split();
- decode_block(a, at, ap);
- decode_block(b, bt, bp);
+ let [a, b] = unsafe { std::mem::transmute::<_, [&'static Block; 2]>([a, b]) };
+ let [at, bt] = unsafe {
+ std::mem::transmute::<_, [View<&'static mut Frame>; 2]>(target.split_mut_unsafe())
+ };
+ let [ap, bp] =
+ unsafe { std::mem::transmute::<_, [View<&'static Frame>; 2]>(prev.split()) };
+ let config = unsafe { std::mem::transmute::<_, &'static DecodeConfig>(config) };
+
+ both_par(
+ move || decode_block(a, at, ap, config),
+ move || decode_block(b, bt, bp, config),
+ config.max_threads,
+ );
}
Block::Reference { translation } => target.copy_from(&prev.offset(*translation)),
Block::AdvancedReference(r) => target.copy_from_sampler(&Sampler::from_refblock(prev, r)),
diff --git a/evc/src/codec/encode.rs b/evc/src/codec/encode.rs
index 4eb86b5..6b6f8a3 100644
--- a/evc/src/codec/encode.rs
+++ b/evc/src/codec/encode.rs
@@ -6,7 +6,6 @@ use crate::{
view::View,
};
use clap::ValueEnum;
-use log::debug;
#[derive(Debug, Clone)]
pub struct EncodeConfig {
@@ -15,15 +14,38 @@ pub struct EncodeConfig {
pub max_diff_area: isize,
pub min_block_size: isize,
pub max_threads: usize,
+ pub weight_factor: f64,
+ pub do_value_scale: bool,
+ pub do_matrix_transform: bool,
}
#[derive(Debug, Clone, ValueEnum)]
pub enum EncodeMode {
Trivial,
+ Fast,
Default,
Advanced,
}
+#[inline]
+pub fn pk<F: FnMut(&mut AdvancedReference) -> ()>(
+ view: &View<&Frame>,
+ prev: &View<&Frame>,
+ diff: &mut f64,
+ params: &mut AdvancedReference,
+ initial_params: &AdvancedReference,
+ mut f: F,
+) {
+ let mut p = initial_params.clone();
+ f(&mut p);
+ let sampler = Sampler::from_refblock(prev.clone(), &p);
+ let d = View::diff_sampler(view, &sampler);
+ if d < *diff {
+ *diff = d;
+ *params = p;
+ }
+}
+
pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfig) -> Block {
let (diff, refblock) = if view.area() > config.max_diff_area {
(
@@ -33,7 +55,9 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi
},
)
} else {
- match config.mode {
+ let weight = importance(&view).max(0.5);
+ let irrelevance = config.weight_factor / weight;
+ let (diff, refblock) = match config.mode {
EncodeMode::Trivial => (
View::diff(&view, &prev) / view.area() as f64,
Block::Reference {
@@ -41,87 +65,95 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi
},
),
EncodeMode::Default => {
- let mut best_diff = f64::INFINITY;
- let mut best_translation = Vec2::<isize>::ZERO;
+ let mut diff = f64::INFINITY;
+ let mut translation = Vec2::<isize>::ZERO;
const OFFSETS: &[isize] =
&[-64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64];
for x in OFFSETS {
for y in OFFSETS {
- let translation = Vec2 { x: *x, y: *y };
- let diff = View::diff(&view, &prev.offset(translation));
- if diff < best_diff {
- best_translation = translation;
- best_diff = diff;
+ let t = Vec2 { x: *x, y: *y };
+ let d = View::diff(&view, &prev.offset(t));
+ if d < diff {
+ translation = t;
+ diff = d;
}
}
}
- (
- best_diff,
- Block::Reference {
- translation: best_translation,
- },
- )
+ (diff, Block::Reference { translation })
}
- EncodeMode::Advanced => {
- let mut params = AdvancedReference::default();
- let sampler = Sampler::from_refblock(prev.clone(), &params);
+ EncodeMode::Fast => {
+ let mut pm = AdvancedReference::default();
+ let sampler = Sampler::from_refblock(prev.clone(), &pm);
let mut diff = View::diff_sampler(&view, &sampler);
-
- loop {
- pub fn pk<F: FnMut(&mut AdvancedReference) -> ()>(
- view: &View<&Frame>,
- prev: &View<&Frame>,
- diff: &mut f64,
- params: &mut AdvancedReference,
- mut f: F,
- ) {
- let mut p = params.clone();
- f(&mut p);
- let d = View::diff_sampler(view, &Sampler::from_refblock(prev.clone(), &p));
- if d < *diff {
- *diff = d;
- *params = p;
+ if diff - irrelevance < config.ref_thres {
+ (diff, Block::REFZERO)
+ } else {
+ loop {
+ let (mut d, mut p) = (diff, pm.clone());
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 2);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 2);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 2);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 2);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 1);
+ if d >= diff {
+ break (diff, Block::AdvancedReference(pm));
}
+ diff = d;
+ pm = p;
}
+ }
+ }
+ EncodeMode::Advanced => {
+ let mut pm = AdvancedReference::default();
+ let sampler = Sampler::from_refblock(prev.clone(), &pm);
+ let mut diff = View::diff_sampler(&view, &sampler);
+ if diff - irrelevance < config.ref_thres {
+ (diff, Block::REFZERO)
+ } else {
+ loop {
+ let (mut d, mut p) = (diff, pm.clone());
- let (mut d, mut p) = (diff, params.clone());
-
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x += 4);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x -= 4);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y += 4);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y -= 4);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x += 2);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x -= 2);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y += 2);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y -= 2);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.x -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.translation.y -= 1);
-
- pk(&view, &prev, &mut d, &mut p, |p| p.value_scale += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.value_scale -= 1);
-
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.a -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.a += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.b -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.b += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.c -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.c += 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.d -= 1);
- pk(&view, &prev, &mut d, &mut p, |p| p.transform.d += 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 4);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 4);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 4);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 4);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 2);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 2);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 2);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 2);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x += 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.x -= 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y += 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.translation.y -= 1);
+ if config.do_value_scale {
+ // pk(&view, &prev, &mut d, &mut p, &pm, |p| p.value_scale += 1);
+ // pk(&view, &prev, &mut d, &mut p, &pm, |p| p.value_scale -= 1);
+ }
+ if config.do_matrix_transform {
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.a -= 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.a += 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.b -= 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.b += 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.c -= 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.c += 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.d -= 1);
+ pk(&view, &prev, &mut d, &mut p, &pm, |p| p.transform.d += 1);
+ }
- debug!("{diff} -> {d}");
+ if d >= diff {
+ break (diff, Block::AdvancedReference(pm));
+ }
- if d >= diff {
- break (diff, Block::AdvancedReference(params));
+ diff = d;
+ pm = p;
}
-
- diff = d;
- params = p;
}
}
- }
+ };
+ (diff - irrelevance, refblock)
};
if diff < config.ref_thres {
refblock
@@ -136,18 +168,23 @@ pub fn encode_block(view: View<&Frame>, prev: View<&Frame>, config: &EncodeConfi
let config = unsafe { std::mem::transmute::<_, &'static EncodeConfig>(config) };
// only bother to do multithreading, when the block is big.
- let (a, b) = if view.size.x > 64 {
+ let (a, b) = // if view.size.x > 64 {
both_par(
|| encode_block(av, ap, config),
|| encode_block(bv, bp, config),
config.max_threads,
)
- } else {
- (encode_block(av, ap, config), encode_block(bv, bp, config))
- };
+ // } else {
+ // (encode_block(av, ap, config), encode_block(bv, bp, config))
+ // }
+ ;
if a.is_literal() && b.is_literal() {
Block::Literal(view.pixels())
+ } else if a.is_ref_without_translation() && b.is_ref_without_translation() {
+ Block::Reference {
+ translation: Vec2::<isize>::ZERO,
+ }
} else {
Block::Split(Box::new([a, b]))
}
diff --git a/evc/src/format/ser.rs b/evc/src/format/ser.rs
index 817cafe..995ca75 100644
--- a/evc/src/format/ser.rs
+++ b/evc/src/format/ser.rs
@@ -103,6 +103,28 @@ impl<T: Ser> Ser for Vec<T> {
}
}
+pub trait ConstSizeSerExt: Sized {
+ fn write_const_size(&self, sink: &mut impl Write, size: usize) -> anyhow::Result<()>;
+ fn read_const_size(source: &mut impl Read, size: usize) -> anyhow::Result<Self>;
+}
+impl<T: Ser> ConstSizeSerExt for Vec<T> {
+ fn write_const_size(&self, sink: &mut impl Write, size: usize) -> anyhow::Result<()> {
+ assert_eq!(self.len(), size);
+ for e in self {
+ e.write(sink).context("some const-size vec")?;
+ }
+ Ok(())
+ }
+
+ fn read_const_size(source: &mut impl Read, size: usize) -> anyhow::Result<Self> {
+ let mut v = vec![];
+ for _ in 0..size {
+ v.push(T::read(source)?)
+ }
+ Ok(v)
+ }
+}
+
impl Ser for u8 {
fn write(&self, sink: &mut impl Write) -> anyhow::Result<()> {
Ok(sink.write_all(&[*self]).context("write u8")?)
diff --git a/evc/src/helpers/pixel.rs b/evc/src/helpers/pixel.rs
index 964040d..816d7dc 100644
--- a/evc/src/helpers/pixel.rs
+++ b/evc/src/helpers/pixel.rs
@@ -27,17 +27,16 @@ impl Pixel {
a.r.abs_diff(b.r) as usize,
a.r.abs_diff(b.r) as usize,
);
+ // fast_sqrt(rd * rd + gd * gd + bd * bd)
SQRT[rd + gd + bd]
}
-
+
#[inline]
pub fn average(a: Pixel, b: Pixel) -> Pixel {
- //? this functions is broken
- // TODO dont loose accuracy
Pixel {
- r: (a.r >> 1) + (b.r >> 1),
- g: (a.g >> 1) + (b.g >> 1),
- b: (a.b >> 1) + (b.b >> 1),
+ r: ((a.r as u16 + b.r as u16) >> 1) as u8,
+ g: ((a.g as u16 + b.g as u16) >> 1) as u8,
+ b: ((a.b as u16 + b.b as u16) >> 1) as u8,
}
}
@@ -51,7 +50,7 @@ impl Pixel {
}
}
-const SQRT: [usize; 256 * 3] = gen_sqrt_lookup();
+pub const SQRT: [usize; 256 * 3] = gen_sqrt_lookup();
const fn gen_sqrt_lookup<const N: usize>() -> [usize; N] {
let mut arr = [0; N];
@@ -70,3 +69,12 @@ const fn sqrt(x: f32) -> f32 {
let a = (a + x / a) * 0.5;
a
}
+
+pub fn fast_sqrt(x: usize) -> usize {
+ let a = 1;
+ let a = (a + x / (a + 1)) / 2;
+ let a = (a + x / (a + 1)) / 2;
+ // let a = (a + x / (a + 1)) / 2;
+ // let a = (a + x / (a + 1)) / 2;
+ a
+}
diff --git a/evc/src/helpers/vector.rs b/evc/src/helpers/vector.rs
index f411832..7cb180a 100644
--- a/evc/src/helpers/vector.rs
+++ b/evc/src/helpers/vector.rs
@@ -31,6 +31,9 @@ impl<T: std::ops::Mul<Output = T> + Copy> Vec2<T> {
y: self.y * f,
}
}
+ pub fn area(&self) -> T {
+ self.x * self.y
+ }
}
impl Vec2<isize> {
diff --git a/evc/src/refsampler.rs b/evc/src/refsampler.rs
index d6f2bb1..a9a6d29 100644
--- a/evc/src/refsampler.rs
+++ b/evc/src/refsampler.rs
@@ -22,7 +22,7 @@ impl<'a> Sampler<'a> {
pub fn sample(&self, p: Vec2<f32>) -> Pixel {
self.view
.sample(self.translation + self.transform.transform(p + self.halfsize) - self.halfsize)
- .scale(self.value_scale)
+ // .scale(self.value_scale)
}
pub fn from_refblock(
view: View<&'a Frame>,