pbrt/shared/src/core/pbrt.rs

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
);
}
}
}
};
}
}