From 7e768b84e49967138d3afa41521fccb42d99fca0 Mon Sep 17 00:00:00 2001 From: Acrimon Date: Tue, 24 Sep 2019 11:05:01 +0200 Subject: [PATCH 1/3] Fast powf for sgrb. --- common/src/util/mod.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/common/src/util/mod.rs b/common/src/util/mod.rs index 09fb4d6acc..165260c990 100644 --- a/common/src/util/mod.rs +++ b/common/src/util/mod.rs @@ -2,6 +2,23 @@ pub const GIT_HASH: &str = include_str!(concat!(env!("OUT_DIR"), "/githash")); use vek::{Mat3, Rgb, Rgba, Vec3}; +#[inline(always)] +#[allow(unsafe_code)] +fn fast_powf(b: f32, e: f32) -> f32 { + unsafe { + let b = b as f64; + let e = e as f64; + union Swagger { + f: f64, + a: [i32; 2], + } + let mut b = Swagger { f: b }; + b.a[1] = (e * (b.a[1] as f64 - 1072632447.0) + 1072632447.0) as i32; + b.a[0] = 0; + b.f as f32 + } +} + #[inline(always)] pub fn srgb_to_linear(col: Rgb) -> Rgb { #[inline(always)] @@ -9,7 +26,7 @@ pub fn srgb_to_linear(col: Rgb) -> Rgb { if x <= 0.04045 { x / 12.92 } else { - ((x + 0.055) / 1.055).powf(2.4) + fast_powf((x + 0.055) / 1.055, 2.4) } } col.map(to_linear) @@ -21,7 +38,7 @@ pub fn linear_to_srgb(col: Rgb) -> Rgb { if x <= 0.0031308 { x * 12.92 } else { - x.powf(1.0 / 2.4) * 1.055 - 0.055 + fast_powf(x, 1.0 / 2.4) * 1.055 - 0.055 } } col.map(to_srgb) @@ -118,6 +135,7 @@ pub fn xyy_to_rgb(xyy: Vec3) -> Rgb { ) } +// TO-DO: speed this up #[inline(always)] pub fn saturate_srgb(col: Rgb, value: f32) -> Rgb { let mut hsv = rgb_to_hsv(srgb_to_linear(col)); From 3db0b2946de90286900ee832508953ad865924a1 Mon Sep 17 00:00:00 2001 From: Acrimon Date: Tue, 24 Sep 2019 11:36:35 +0200 Subject: [PATCH 2/3] Added some tests. --- common/src/util/mod.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/common/src/util/mod.rs b/common/src/util/mod.rs index 165260c990..d0694f0631 100644 --- a/common/src/util/mod.rs +++ b/common/src/util/mod.rs @@ -2,9 +2,10 @@ pub const GIT_HASH: &str = include_str!(concat!(env!("OUT_DIR"), "/githash")); use vek::{Mat3, Rgb, Rgba, Vec3}; +/// This is a fast approximation of powf. This should only be used when minor accuracy loss is acceptable. #[inline(always)] #[allow(unsafe_code)] -fn fast_powf(b: f32, e: f32) -> f32 { +fn approx_powf(b: f32, e: f32) -> f32 { unsafe { let b = b as f64; let e = e as f64; @@ -19,6 +20,21 @@ fn fast_powf(b: f32, e: f32) -> f32 { } } +#[cfg(test)] +mod approx_powf_tests { + fn close_ei(a: f32, b: f32) -> bool { + (a - b < 1.0 && a - b > 0.0) || (b - a < 1.0 && b - a > 0.0) + } + + #[test] + fn accuracy_1() { + let test_values: Vec = vec!(3.0, 2.5, 1.5, 2.2); + test_values.windows(2).for_each(|a| { + assert!(close_ei(a[0].powf(a[1]), super::approx_powf(a[0], a[1]))); + }); + } +} + #[inline(always)] pub fn srgb_to_linear(col: Rgb) -> Rgb { #[inline(always)] @@ -26,7 +42,7 @@ pub fn srgb_to_linear(col: Rgb) -> Rgb { if x <= 0.04045 { x / 12.92 } else { - fast_powf((x + 0.055) / 1.055, 2.4) + approx_powf((x + 0.055) / 1.055, 2.4) } } col.map(to_linear) @@ -38,7 +54,7 @@ pub fn linear_to_srgb(col: Rgb) -> Rgb { if x <= 0.0031308 { x * 12.92 } else { - fast_powf(x, 1.0 / 2.4) * 1.055 - 0.055 + approx_powf(x, 1.0 / 2.4) * 1.055 - 0.055 } } col.map(to_srgb) From 9ce9251a175852d2ee77e2311294e15c6bd56eff Mon Sep 17 00:00:00 2001 From: Acrimon Date: Tue, 24 Sep 2019 11:56:19 +0200 Subject: [PATCH 3/3] Formatted code. --- common/src/util/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/util/mod.rs b/common/src/util/mod.rs index d0694f0631..cb443ef2fd 100644 --- a/common/src/util/mod.rs +++ b/common/src/util/mod.rs @@ -28,7 +28,7 @@ mod approx_powf_tests { #[test] fn accuracy_1() { - let test_values: Vec = vec!(3.0, 2.5, 1.5, 2.2); + let test_values: Vec = vec![3.0, 2.5, 1.5, 2.2]; test_values.windows(2).for_each(|a| { assert!(close_ei(a[0].powf(a[1]), super::approx_powf(a[0], a[1]))); });