146 lines
4 KiB
Rust
146 lines
4 KiB
Rust
use crate::core::geometry::Lerp;
|
|
use core::ops::{Add, Mul};
|
|
use num_traits::{Num, PrimInt};
|
|
|
|
use crate::core::image::DeviceImage;
|
|
use crate::core::light::LightTrait;
|
|
use crate::core::shape::Shape;
|
|
use crate::core::texture::GPUFloatTexture;
|
|
use crate::lights::*;
|
|
use crate::spectra::{DenselySampledSpectrum, RGBColorSpace};
|
|
use crate::utils::Ptr;
|
|
|
|
pub type Float = f32;
|
|
|
|
#[cfg(not(feature = "use_f64"))]
|
|
pub type FloatBits = u32;
|
|
|
|
#[cfg(feature = "use_f64")]
|
|
pub type FloatBits = u64;
|
|
|
|
pub trait FloatBitOps: Copy {
|
|
type Bits;
|
|
|
|
fn to_bits_val(self) -> Self::Bits;
|
|
fn exponent_val(self) -> i32;
|
|
fn significand_val(self) -> Self::Bits;
|
|
fn sign_bit_val(self) -> Self::Bits;
|
|
fn from_bits_val(bits: Self::Bits) -> Self;
|
|
}
|
|
|
|
impl FloatBitOps for f32 {
|
|
type Bits = u32;
|
|
|
|
#[inline(always)]
|
|
fn to_bits_val(self) -> u32 {
|
|
self.to_bits()
|
|
}
|
|
|
|
// Shift 23, Mask 8 bits (0xFF), Bias 127
|
|
#[inline(always)]
|
|
fn exponent_val(self) -> i32 {
|
|
let bits = self.to_bits();
|
|
((bits >> 23) & 0xFF) as i32 - 127
|
|
}
|
|
|
|
// Mask bottom 23 bits
|
|
#[inline(always)]
|
|
fn significand_val(self) -> u32 {
|
|
self.to_bits() & ((1 << 23) - 1)
|
|
}
|
|
|
|
// Mask top bit (31)
|
|
#[inline(always)]
|
|
fn sign_bit_val(self) -> u32 {
|
|
self.to_bits() & 0x8000_0000
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn from_bits_val(bits: u32) -> Self {
|
|
Self::from_bits(bits)
|
|
}
|
|
}
|
|
|
|
impl FloatBitOps for f64 {
|
|
type Bits = u64;
|
|
|
|
#[inline(always)]
|
|
fn to_bits_val(self) -> u64 {
|
|
self.to_bits()
|
|
}
|
|
|
|
// Shift 52, Mask 11 bits (0x7FF), Bias 1023
|
|
#[inline(always)]
|
|
fn exponent_val(self) -> i32 {
|
|
let bits = self.to_bits();
|
|
((bits >> 52) & 0x7FF) as i32 - 1023
|
|
}
|
|
|
|
// Mask bottom 52 bits
|
|
#[inline(always)]
|
|
fn significand_val(self) -> u64 {
|
|
self.to_bits() & ((1u64 << 52) - 1)
|
|
}
|
|
|
|
// Mask top bit (63)
|
|
#[inline(always)]
|
|
fn sign_bit_val(self) -> u64 {
|
|
self.to_bits() & 0x8000_0000_0000_0000
|
|
}
|
|
|
|
#[inline(always)]
|
|
fn from_bits_val(bits: u64) -> Self {
|
|
Self::from_bits(bits)
|
|
}
|
|
}
|
|
|
|
pub const MACHINE_EPSILON: Float = Float::EPSILON * 0.5;
|
|
pub const SHADOW_EPSILON: Float = 0.0001;
|
|
pub const ONE_MINUS_EPSILON: Float = 0.99999994;
|
|
pub const PI: Float = core::f32::consts::PI;
|
|
pub const INV_PI: Float = core::f32::consts::FRAC_1_PI;
|
|
pub const INV_2_PI: Float = 0.159_154_943_091_895_335_77;
|
|
pub const INV_4_PI: Float = 0.079_577_471_545_947_667_88;
|
|
pub const PI_OVER_2: Float = core::f32::consts::FRAC_PI_2;
|
|
pub const PI_OVER_4: Float = core::f32::consts::FRAC_PI_4;
|
|
pub const SQRT_2: Float = core::f32::consts::SQRT_2;
|
|
|
|
#[inline]
|
|
pub fn gamma(n: i32) -> Float {
|
|
n as Float * MACHINE_EPSILON / (1. - n as Float * MACHINE_EPSILON)
|
|
}
|
|
|
|
#[cfg(feature = "cpu_debug")]
|
|
pub mod debug {
|
|
use core::sync::atomic::AtomicU64;
|
|
use core::sync::atomic::Ordering as SyncOrdering;
|
|
pub static RARE_EVENT_TOTAL_CALLS: AtomicU64 = AtomicU64::new(0);
|
|
pub static RARE_EVENT_CONDITION_MET: AtomicU64 = AtomicU64::new(0);
|
|
|
|
#[macro_export]
|
|
macro_rules! check_rare {
|
|
($frequency_threshold:expr, $condition:expr) => {
|
|
use core::sync::atomic::{AtomicU64, Ordering as SyncOrdering};
|
|
const CHECK_INTERVAL: u64 = 4096;
|
|
|
|
let total_calls = RARE_EVENT_TOTAL_CALLS.fetch_add(1, SyncOrdering::Relaxed);
|
|
|
|
if $condition {
|
|
RARE_EVENT_CONDITION_MET.fetch_add(1, SyncOrdering::Relaxed);
|
|
}
|
|
|
|
if (total_calls + 1) % CHECK_INTERVAL == 0 {
|
|
let met_count = RARE_EVENT_CONDITION_MET.load(SyncOrdering::Relaxed);
|
|
if met_count > 0 {
|
|
let frequency = met_count as f64 / (total_calls + 1) as f64;
|
|
if frequency > $frequency_threshold {
|
|
panic!(
|
|
"Rare event occurred with frequency {} which is > threshold {}",
|
|
frequency, $frequency_threshold
|
|
);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|